From 8362bf63dea22bbf6736609b0f49c152f975eb63 Mon Sep 17 00:00:00 2001 From: tpearson Date: Wed, 20 Jan 2010 01:29:50 +0000 Subject: Added old abandoned KDE3 version of koffice git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/koffice@1077364 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- krita/AUTHORS | 20 + krita/ChangeLog | 1 + krita/HACKING | 93 + krita/IMAGE_LIBRARIES | 259 + krita/Makefile.am | 47 + krita/README | 13 + krita/TODO | 181 + krita/UIcomments | 59 + krita/colorspaces/Makefile.am | 15 + krita/colorspaces/README | 11 + krita/colorspaces/cmyk_u16/Makefile.am | 30 + krita/colorspaces/cmyk_u16/cmyk_u16_plugin.cc | 61 + krita/colorspaces/cmyk_u16/cmyk_u16_plugin.h | 37 + .../cmyk_u16/kis_cmyk_u16_colorspace.cc | 714 + .../colorspaces/cmyk_u16/kis_cmyk_u16_colorspace.h | 123 + .../cmyk_u16/krita_cmyk_u16_plugin.desktop | 85 + krita/colorspaces/cmyk_u8/Makefile.am | 20 + krita/colorspaces/cmyk_u8/cmyk_plugin.cc | 66 + krita/colorspaces/cmyk_u8/cmyk_plugin.h | 37 + krita/colorspaces/cmyk_u8/cmykplugin.rc | 7 + krita/colorspaces/cmyk_u8/composite.h | 76 + krita/colorspaces/cmyk_u8/kis_cmyk_colorspace.cc | 710 + krita/colorspaces/cmyk_u8/kis_cmyk_colorspace.h | 126 + krita/colorspaces/cmyk_u8/kritacmykplugin.desktop | 99 + krita/colorspaces/cmyk_u8/templates/.directory | 5 + krita/colorspaces/cmyk_u8/templates/Makefile.am | 8 + .../templates/cr48-action-template_cmyk_empty.png | Bin 0 -> 431 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 krita/colorspaces/gray_u16/Makefile.am | 29 + krita/colorspaces/gray_u16/gray_u16_plugin.cc | 63 + krita/colorspaces/gray_u16/gray_u16_plugin.h | 37 + .../gray_u16/kis_gray_u16_colorspace.cc | 658 + .../colorspaces/gray_u16/kis_gray_u16_colorspace.h | 118 + .../gray_u16/krita_gray_u16_plugin.desktop | 83 + krita/colorspaces/gray_u8/Makefile.am | 31 + krita/colorspaces/gray_u8/gray_plugin.cc | 77 + krita/colorspaces/gray_u8/gray_plugin.h | 36 + krita/colorspaces/gray_u8/grayplugin.rc | 7 + krita/colorspaces/gray_u8/kis_gray_colorspace.cc | 997 + krita/colorspaces/gray_u8/kis_gray_colorspace.h | 114 + krita/colorspaces/gray_u8/kritagrayplugin.desktop | 97 + krita/colorspaces/gray_u8/templates/.directory | 48 + krita/colorspaces/gray_u8/templates/Makefile.am | 8 + .../templates/cr48-action-template_gray_empty.png | Bin 0 -> 1367 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 krita/colorspaces/gray_u8/tests/Makefile.am | 17 + .../kis_strategy_colorspace_grayscale_tester.cpp | 155 + .../kis_strategy_colorspace_grayscale_tester.h | 34 + krita/colorspaces/lms_f32/Makefile.am | 28 + .../colorspaces/lms_f32/kis_lms_f32_colorspace.cc | 385 + krita/colorspaces/lms_f32/kis_lms_f32_colorspace.h | 157 + .../lms_f32/krita_lms_f32_plugin.desktop | 77 + krita/colorspaces/lms_f32/lms_f32_plugin.cc | 64 + krita/colorspaces/lms_f32/lms_f32_plugin.h | 39 + krita/colorspaces/lms_f32/lms_f32_plugin.rc | 9 + krita/colorspaces/rgb_f16half/Makefile.am | 35 + .../rgb_f16half/kis_rgb_f16half_colorspace.cc | 952 + .../rgb_f16half/kis_rgb_f16half_colorspace.h | 144 + .../rgb_f16half/krita_rgb_f16half_plugin.desktop | 76 + .../colorspaces/rgb_f16half/rgb_f16half_plugin.cc | 63 + krita/colorspaces/rgb_f16half/rgb_f16half_plugin.h | 38 + .../colorspaces/rgb_f16half/rgb_f16half_plugin.rc | 9 + krita/colorspaces/rgb_f16half/tests/Makefile.am | 19 + .../tests/kis_rgb_f16half_colorspace_tester.cc | 545 + .../tests/kis_rgb_f16half_colorspace_tester.h | 47 + krita/colorspaces/rgb_f32/Makefile.am | 34 + .../colorspaces/rgb_f32/kis_rgb_f32_colorspace.cc | 949 + krita/colorspaces/rgb_f32/kis_rgb_f32_colorspace.h | 165 + .../rgb_f32/krita_rgb_f32_plugin.desktop | 77 + krita/colorspaces/rgb_f32/rgb_f32_plugin.cc | 63 + krita/colorspaces/rgb_f32/rgb_f32_plugin.h | 38 + krita/colorspaces/rgb_f32/rgb_f32_plugin.rc | 9 + krita/colorspaces/rgb_f32/tests/Makefile.am | 17 + .../kis_strategy_colorspace_rgb_f32_tester.cc | 541 + .../tests/kis_strategy_colorspace_rgb_f32_tester.h | 47 + krita/colorspaces/rgb_u16/Makefile.am | 32 + .../colorspaces/rgb_u16/kis_rgb_u16_colorspace.cc | 869 + krita/colorspaces/rgb_u16/kis_rgb_u16_colorspace.h | 128 + .../rgb_u16/krita_rgb_u16_plugin.desktop | 80 + krita/colorspaces/rgb_u16/rgb_u16_plugin.cc | 61 + krita/colorspaces/rgb_u16/rgb_u16_plugin.h | 36 + krita/colorspaces/rgb_u16/tests/Makefile.am | 17 + .../kis_strategy_colorspace_rgb_u16_tester.cc | 524 + .../tests/kis_strategy_colorspace_rgb_u16_tester.h | 46 + krita/colorspaces/rgb_u8/Makefile.am | 33 + krita/colorspaces/rgb_u8/composite.h | 868 + krita/colorspaces/rgb_u8/kis_rgb_colorspace.cc | 1501 + krita/colorspaces/rgb_u8/kis_rgb_colorspace.h | 116 + krita/colorspaces/rgb_u8/kritargbplugin.desktop | 99 + krita/colorspaces/rgb_u8/rgb_plugin.cc | 74 + krita/colorspaces/rgb_u8/rgb_plugin.h | 37 + krita/colorspaces/rgb_u8/rgbplugin.rc | 9 + krita/colorspaces/rgb_u8/templates/.directory | 6 + krita/colorspaces/rgb_u8/templates/Makefile.am | 8 + .../templates/cr48-action-template_rgb_empty.png | Bin 0 -> 2363 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 krita/colorspaces/rgb_u8/tests/Makefile.am | 17 + .../tests/kis_strategy_colorspace_rgb_tester.cpp | 197 + .../tests/kis_strategy_colorspace_rgb_tester.h | 34 + krita/colorspaces/wet/Makefile.am | 27 + krita/colorspaces/wet/kis_texture_filter.cc | 43 + krita/colorspaces/wet/kis_texture_filter.h | 38 + krita/colorspaces/wet/kis_texture_painter.cc | 92 + krita/colorspaces/wet/kis_texture_painter.h | 40 + krita/colorspaces/wet/kis_wet_colorspace.cc | 514 + krita/colorspaces/wet/kis_wet_colorspace.h | 219 + krita/colorspaces/wet/kis_wet_palette_widget.cc | 245 + krita/colorspaces/wet/kis_wet_palette_widget.h | 67 + .../wet/kis_wetness_visualisation_filter.cc | 77 + .../wet/kis_wetness_visualisation_filter.h | 50 + krita/colorspaces/wet/kis_wetop.cc | 230 + krita/colorspaces/wet/kis_wetop.h | 73 + krita/colorspaces/wet/kritawetplugin.desktop | 86 + krita/colorspaces/wet/todo | 24 + krita/colorspaces/wet/wdgpressure.ui | 60 + krita/colorspaces/wet/wet_plugin.cc | 128 + krita/colorspaces/wet/wet_plugin.h | 45 + krita/colorspaces/wet/wetdreams/Makefile | 6 + krita/colorspaces/wet/wetdreams/wetmain.c | 517 + krita/colorspaces/wet/wetdreams/wetpaint.c | 101 + krita/colorspaces/wet/wetdreams/wetpaint.h | 4 + krita/colorspaces/wet/wetdreams/wetphysics.c | 334 + krita/colorspaces/wet/wetdreams/wetphysics.h | 9 + krita/colorspaces/wet/wetdreams/wetpix.c | 332 + krita/colorspaces/wet/wetdreams/wetpix.h | 87 + krita/colorspaces/wet/wetdreams/wettexture.c | 84 + krita/colorspaces/wet/wetdreams/wettexture.h | 9 + krita/colorspaces/wet/wetphysicsfilter.cc | 424 + krita/colorspaces/wet/wetphysicsfilter.h | 87 + krita/colorspaces/wet/wetplugin.rc | 8 + krita/colorspaces/wetsticky/Makefile.am | 25 + krita/colorspaces/wetsticky/README | 42 + krita/colorspaces/wetsticky/TODO | 7 + krita/colorspaces/wetsticky/brushop/Makefile.am | 28 + krita/colorspaces/wetsticky/brushop/README | 2 + .../colorspaces/wetsticky/brushop/kis_wsbrushop.cc | 117 + .../colorspaces/wetsticky/brushop/kis_wsbrushop.h | 56 + .../wetsticky/brushop/kritawsbrushpaintop.desktop | 73 + .../wetsticky/brushop/wetpaintbrush.png | Bin 0 -> 1328 bytes .../wetsticky/brushop/wsbrushpaintop_plugin.cc | 56 + .../wetsticky/brushop/wsbrushpaintop_plugin.h | 43 + .../wetsticky/kis_wet_sticky_colorspace.cc | 605 + .../wetsticky/kis_wet_sticky_colorspace.h | 148 + .../colorspaces/wetsticky/kis_ws_engine_filter.cc | 180 + krita/colorspaces/wetsticky/kis_ws_engine_filter.h | 77 + krita/colorspaces/wetsticky/kritawsplugin.desktop | 46 + krita/colorspaces/wetsticky/wet_sticky_plugin.cc | 60 + krita/colorspaces/wetsticky/wet_sticky_plugin.h | 41 + krita/colorspaces/wetsticky/ws/GNU | 0 .../wetsticky/ws/GNU Public Licence.txt | 341 + krita/colorspaces/wetsticky/ws/README | 4 + krita/colorspaces/wetsticky/ws/TODO | 24 + krita/colorspaces/wetsticky/ws/after.jpg | Bin 0 -> 29607 bytes krita/colorspaces/wetsticky/ws/anim.c | 154 + krita/colorspaces/wetsticky/ws/before.jpg | Bin 0 -> 15496 bytes krita/colorspaces/wetsticky/ws/canvas.c | 514 + krita/colorspaces/wetsticky/ws/canvas.h | 70 + krita/colorspaces/wetsticky/ws/cmap.c | 681 + krita/colorspaces/wetsticky/ws/constants.h | 69 + krita/colorspaces/wetsticky/ws/engine.c | 802 + krita/colorspaces/wetsticky/ws/engine.h | 33 + krita/colorspaces/wetsticky/ws/engine3.c | 617 + krita/colorspaces/wetsticky/ws/load_ppm.c | 244 + krita/colorspaces/wetsticky/ws/main.c | 105 + krita/colorspaces/wetsticky/ws/makefile | 55 + krita/colorspaces/wetsticky/ws/mona.pgm | Bin 0 -> 86269 bytes krita/colorspaces/wetsticky/ws/ogl_interface.c | 302 + krita/colorspaces/wetsticky/ws/test2.jpg | Bin 0 -> 13050 bytes krita/colorspaces/wetsticky/ws/test3.jpg | Bin 0 -> 21238 bytes krita/colorspaces/wetsticky/ws/types.h | 72 + krita/colorspaces/wetsticky/ws/win_interface.h | 28 + krita/colorspaces/wetsticky/ws/x_interface.c | 795 + krita/colorspaces/wetsticky/wstool.ui | 262 + krita/colorspaces/ycbcr_u16/Makefile.am | 27 + .../ycbcr_u16/kis_ycbcr_u16_colorspace.cc | 338 + .../ycbcr_u16/kis_ycbcr_u16_colorspace.h | 144 + .../ycbcr_u16/krita_ycbcr_u16_plugin.desktop | 71 + krita/colorspaces/ycbcr_u16/ycbcr_u16_plugin.cc | 60 + krita/colorspaces/ycbcr_u16/ycbcr_u16_plugin.h | 37 + krita/colorspaces/ycbcr_u8/Makefile.am | 29 + .../ycbcr_u8/kis_ycbcr_u8_colorspace.cc | 344 + .../colorspaces/ycbcr_u8/kis_ycbcr_u8_colorspace.h | 144 + .../ycbcr_u8/krita_ycbcr_u8_plugin.desktop | 71 + krita/colorspaces/ycbcr_u8/ycbcr_u8_plugin.cc | 62 + krita/colorspaces/ycbcr_u8/ycbcr_u8_plugin.h | 37 + krita/configure.in.bot | 19 + krita/configure.in.in | 110 + krita/core/Makefile.am | 59 + krita/core/createdcop.py | 171 + krita/core/kis_adjustment_layer.cc | 252 + krita/core/kis_adjustment_layer.h | 105 + krita/core/kis_alpha_mask.cc | 132 + krita/core/kis_alpha_mask.h | 106 + krita/core/kis_autobrush_resource.cc | 106 + krita/core/kis_autobrush_resource.h | 71 + krita/core/kis_autogradient_resource.cc | 221 + krita/core/kis_autogradient_resource.h | 88 + krita/core/kis_background.cc | 155 + krita/core/kis_background.h | 49 + krita/core/kis_basic_math_toolbox.cpp | 137 + krita/core/kis_basic_math_toolbox.h | 44 + krita/core/kis_boundary.cc | 83 + krita/core/kis_boundary.h | 57 + krita/core/kis_brush.cc | 1333 + krita/core/kis_brush.h | 191 + krita/core/kis_change_profile_visitor.h | 109 + krita/core/kis_colorspace_convert_visitor.h | 101 + krita/core/kis_command.cc | 43 + krita/core/kis_command.h | 55 + krita/core/kis_convolution_painter.cc | 426 + krita/core/kis_convolution_painter.h | 95 + krita/core/kis_crop_visitor.h | 109 + krita/core/kis_datamanager.h | 217 + krita/core/kis_exif_info.cc | 66 + krita/core/kis_exif_info.h | 58 + krita/core/kis_exif_value.cc | 678 + krita/core/kis_exif_value.h | 270 + krita/core/kis_fill_painter.cc | 407 + krita/core/kis_fill_painter.h | 207 + krita/core/kis_filter.cc | 133 + krita/core/kis_filter.h | 200 + krita/core/kis_filter_config_widget.cc | 31 + krita/core/kis_filter_config_widget.h | 49 + krita/core/kis_filter_configuration.cc | 185 + krita/core/kis_filter_configuration.h | 105 + krita/core/kis_filter_registry.cc | 82 + krita/core/kis_filter_registry.h | 52 + krita/core/kis_filter_strategy.cc | 192 + krita/core/kis_filter_strategy.h | 150 + krita/core/kis_gradient.cc | 639 + krita/core/kis_gradient.h | 264 + krita/core/kis_gradient_painter.cc | 723 + krita/core/kis_gradient_painter.h | 84 + krita/core/kis_group_layer.cc | 428 + krita/core/kis_group_layer.h | 140 + krita/core/kis_histogram.cc | 215 + krita/core/kis_histogram.h | 150 + krita/core/kis_image.cc | 1702 + krita/core/kis_image.h | 460 + krita/core/kis_image_iface.cc | 97 + krita/core/kis_image_iface.h | 65 + krita/core/kis_imagepipe_brush.cc | 456 + krita/core/kis_imagepipe_brush.h | 168 + krita/core/kis_iterator.cc | 142 + krita/core/kis_iterator.h | 173 + krita/core/kis_iteratorpixeltrait.h | 131 + krita/core/kis_iterators_pixel.cc | 59 + krita/core/kis_iterators_pixel.h | 154 + krita/core/kis_layer.cc | 611 + krita/core/kis_layer.h | 256 + krita/core/kis_layer_visitor.h | 43 + krita/core/kis_math_toolbox.cpp | 166 + krita/core/kis_math_toolbox.h | 123 + krita/core/kis_merge_visitor.h | 358 + krita/core/kis_meta_registry.cc | 68 + krita/core/kis_meta_registry.h | 49 + krita/core/kis_nameserver.cc | 49 + krita/core/kis_nameserver.h | 40 + krita/core/kis_paint_device.cc | 1285 + krita/core/kis_paint_device.h | 596 + krita/core/kis_paint_device_action.h | 43 + krita/core/kis_paint_device_iface.cc | 74 + krita/core/kis_paint_device_iface.h | 85 + krita/core/kis_paint_layer.cc | 509 + krita/core/kis_paint_layer.h | 156 + krita/core/kis_painter.cc | 928 + krita/core/kis_painter.h | 432 + krita/core/kis_paintop.cc | 113 + krita/core/kis_paintop.h | 141 + krita/core/kis_paintop_registry.cc | 139 + krita/core/kis_paintop_registry.h | 83 + krita/core/kis_palette.cc | 306 + krita/core/kis_palette.h | 112 + krita/core/kis_part_layer_iface.h | 36 + krita/core/kis_pattern.cc | 335 + krita/core/kis_pattern.h | 79 + krita/core/kis_perspective_grid.cpp | 100 + krita/core/kis_perspective_grid.h | 107 + krita/core/kis_perspective_math.cpp | 546 + krita/core/kis_perspective_math.h | 70 + krita/core/kis_perspectivetransform_worker.cpp | 121 + krita/core/kis_perspectivetransform_worker.h | 52 + krita/core/kis_point.h | 48 + krita/core/kis_random_accessor.cpp | 58 + krita/core/kis_random_accessor.h | 95 + krita/core/kis_random_sub_accessor.cpp | 84 + krita/core/kis_random_sub_accessor.h | 45 + krita/core/kis_rect.cc | 28 + krita/core/kis_rect.h | 50 + krita/core/kis_resource.cc | 62 + krita/core/kis_resource.h | 83 + krita/core/kis_rotate_visitor.cc | 406 + krita/core/kis_rotate_visitor.h | 80 + krita/core/kis_scale_visitor.cc | 279 + krita/core/kis_scale_visitor.h | 204 + krita/core/kis_selected_transaction.cc | 73 + krita/core/kis_selected_transaction.h | 50 + krita/core/kis_selection.cc | 582 + krita/core/kis_selection.h | 160 + krita/core/kis_shear_visitor.h | 95 + krita/core/kis_strategy_move.cc | 148 + krita/core/kis_strategy_move.h | 59 + krita/core/kis_substrate.h | 78 + krita/core/kis_thread.h | 57 + krita/core/kis_thread_pool.cc | 192 + krita/core/kis_thread_pool.h | 70 + krita/core/kis_transaction.cc | 94 + krita/core/kis_transaction.h | 46 + krita/core/kis_transform_visitor.h | 137 + krita/core/kis_transform_worker.cc | 676 + krita/core/kis_transform_worker.h | 79 + krita/core/kis_types.h | 90 + krita/core/kis_vec.cc | 67 + krita/core/kis_vec.h | 405 + krita/core/tests/Makefile.am | 30 + .../core/tests/kis_filter_configuration_tester.cc | 67 + krita/core/tests/kis_filter_configuration_tester.h | 34 + krita/core/tests/kis_image_tester.cpp | 88 + krita/core/tests/kis_image_tester.h | 32 + krita/core/tests/kis_integer_maths_tester.cpp | 93 + krita/core/tests/kis_integer_maths_tester.h | 34 + krita/core/tiles/Makefile.am | 23 + krita/core/tiles/kis_memento.cc | 154 + krita/core/tiles/kis_memento.h | 147 + krita/core/tiles/kis_tile.cc | 152 + krita/core/tiles/kis_tile.h | 87 + krita/core/tiles/kis_tile_global.h | 23 + krita/core/tiles/kis_tiled_random_accessor.cc | 115 + krita/core/tiles/kis_tiled_random_accessor.h | 66 + krita/core/tiles/kis_tileddatamanager.cc | 1044 + krita/core/tiles/kis_tileddatamanager.h | 233 + krita/core/tiles/kis_tiledhlineiterator.cc | 213 + krita/core/tiles/kis_tilediterator.cc | 131 + krita/core/tiles/kis_tilediterator.h | 213 + krita/core/tiles/kis_tiledrectiterator.cc | 242 + krita/core/tiles/kis_tiledvlineiterator.cc | 154 + krita/core/tiles/kis_tilemanager.cc | 578 + krita/core/tiles/kis_tilemanager.h | 139 + krita/core/tiles/tests/Makefile.am | 15 + krita/core/tiles/tests/kis_tiled_data_tester.cpp | 74 + krita/core/tiles/tests/kis_tiled_data_tester.h | 32 + krita/data/Makefile.am | 7 + krita/data/README | 13 + krita/data/brushes/10x10square.gbr | Bin 0 -> 143 bytes krita/data/brushes/10x10squareBlur.gbr | Bin 0 -> 148 bytes krita/data/brushes/11circle.gbr | Bin 0 -> 161 bytes krita/data/brushes/11fcircle.gbr | Bin 0 -> 159 bytes krita/data/brushes/13circle.gbr | Bin 0 -> 209 bytes krita/data/brushes/13fcircle.gbr | Bin 0 -> 207 bytes krita/data/brushes/15circle.gbr | Bin 0 -> 265 bytes krita/data/brushes/15fcircle.gbr | Bin 0 -> 263 bytes krita/data/brushes/17circle.gbr | Bin 0 -> 329 bytes krita/data/brushes/17fcircle.gbr | Bin 0 -> 327 bytes krita/data/brushes/19circle.gbr | Bin 0 -> 401 bytes krita/data/brushes/19fcircle.gbr | Bin 0 -> 399 bytes krita/data/brushes/1circle.gbr | Bin 0 -> 41 bytes krita/data/brushes/20x20square.gbr | Bin 0 -> 443 bytes krita/data/brushes/20x20squareBlur.gbr | Bin 0 -> 448 bytes krita/data/brushes/3circle.gbr | Bin 0 -> 49 bytes krita/data/brushes/3fcircle.gbr | Bin 0 -> 47 bytes krita/data/brushes/5circle.gbr | Bin 0 -> 65 bytes krita/data/brushes/5fcircle.gbr | Bin 0 -> 63 bytes krita/data/brushes/5x5square.gbr | Bin 0 -> 66 bytes krita/data/brushes/5x5squareBlur.gbr | Bin 0 -> 71 bytes krita/data/brushes/7circle.gbr | Bin 0 -> 89 bytes krita/data/brushes/7fcircle.gbr | Bin 0 -> 87 bytes krita/data/brushes/9circle.gbr | Bin 0 -> 121 bytes krita/data/brushes/9fcircle.gbr | Bin 0 -> 119 bytes krita/data/brushes/BRUSHES.README | 19 + krita/data/brushes/COPYING | 340 + krita/data/brushes/DStar11.gbr | Bin 0 -> 168 bytes krita/data/brushes/DStar17.gbr | Bin 0 -> 336 bytes krita/data/brushes/DStar25.gbr | Bin 0 -> 672 bytes krita/data/brushes/Makefile.am | 69 + krita/data/brushes/SketchBrush-16.gih | Bin 0 -> 1618 bytes krita/data/brushes/SketchBrush-32.gih | Bin 0 -> 5458 bytes krita/data/brushes/SketchBrush-64.gih | Bin 0 -> 20818 bytes krita/data/brushes/callig1.gbr | Bin 0 -> 147 bytes krita/data/brushes/callig2.gbr | Bin 0 -> 447 bytes krita/data/brushes/callig3.gbr | Bin 0 -> 272 bytes krita/data/brushes/callig4.gbr | Bin 0 -> 72 bytes krita/data/brushes/confetti.gbr | Bin 0 -> 793 bytes krita/data/brushes/confetti.gih | Bin 0 -> 8076 bytes krita/data/brushes/cursor.gbr | Bin 0 -> 899 bytes krita/data/brushes/cursor_big_lb.gbr | Bin 0 -> 2858 bytes krita/data/brushes/cursor_big_lw.gbr | Bin 0 -> 2858 bytes krita/data/brushes/cursor_big_rb.gbr | Bin 0 -> 2858 bytes krita/data/brushes/cursor_big_rw.gbr | Bin 0 -> 2858 bytes krita/data/brushes/cursor_lw.gbr | Bin 0 -> 1802 bytes krita/data/brushes/cursor_resize_diag_1.gbr | Bin 0 -> 1072 bytes krita/data/brushes/cursor_resize_diag_2.gbr | Bin 0 -> 1072 bytes krita/data/brushes/cursor_resize_hor.gbr | Bin 0 -> 958 bytes krita/data/brushes/cursor_resize_vert.gbr | Bin 0 -> 959 bytes krita/data/brushes/cursor_rw.gbr | Bin 0 -> 1802 bytes krita/data/brushes/cursor_small_lb.gbr | Bin 0 -> 1004 bytes krita/data/brushes/cursor_small_lw.gbr | Bin 0 -> 1004 bytes krita/data/brushes/cursor_small_rb.gbr | Bin 0 -> 1004 bytes krita/data/brushes/cursor_small_rw.gbr | Bin 0 -> 1004 bytes krita/data/brushes/cursor_tiny_lw.gbr | Bin 0 -> 523 bytes krita/data/brushes/cursor_tiny_rw.gbr | Bin 0 -> 523 bytes krita/data/brushes/cursor_up.gbr | Bin 0 -> 1606 bytes krita/data/brushes/dunes.gbr | Bin 0 -> 1100 bytes krita/data/brushes/feltpen.gih | Bin 0 -> 118795 bytes krita/data/brushes/galaxy.gbr | Bin 0 -> 2636 bytes krita/data/brushes/galaxy_big.gbr | Bin 0 -> 10037 bytes krita/data/brushes/galaxy_small.gbr | Bin 0 -> 749 bytes krita/data/brushes/hsparks.gih | Bin 0 -> 127644 bytes krita/data/brushes/pepper.gbr | Bin 0 -> 11991 bytes krita/data/brushes/pixel.gbr | Bin 0 -> 48 bytes krita/data/brushes/vine.gih | Bin 0 -> 116027 bytes krita/data/gradients/Abstract_1.ggr | 9 + krita/data/gradients/Abstract_2.ggr | 9 + krita/data/gradients/Abstract_3.ggr | 9 + krita/data/gradients/Aneurism.ggr | 11 + krita/data/gradients/Blinds.ggr | 12 + krita/data/gradients/Blue_Green.ggr | 5 + krita/data/gradients/Browns.ggr | 14 + krita/data/gradients/Brushed_Aluminium.ggr | 27 + krita/data/gradients/Burning_Paper.ggr | 9 + krita/data/gradients/Burning_Transparency.ggr | 9 + krita/data/gradients/CD.ggr | 21 + krita/data/gradients/CD_Half.ggr | 12 + krita/data/gradients/Caribbean_Blues.ggr | 6 + krita/data/gradients/Coffee.ggr | 4 + krita/data/gradients/Cold_Steel.ggr | 5 + krita/data/gradients/Cold_Steel_2.ggr | 6 + krita/data/gradients/Crown_molding.ggr | 9 + krita/data/gradients/Dark_1.ggr | 6 + krita/data/gradients/Deep_Sea.ggr | 5 + krita/data/gradients/Default.ggr | 4 + krita/data/gradients/Flare_Glow_Angular_1.ggr | 49 + krita/data/gradients/Flare_Glow_Radial_1.ggr | 7 + krita/data/gradients/Flare_Glow_Radial_2.ggr | 8 + krita/data/gradients/Flare_Glow_Radial_3.ggr | 8 + krita/data/gradients/Flare_Glow_Radial_4.ggr | 6 + krita/data/gradients/Flare_Radial_101.ggr | 10 + krita/data/gradients/Flare_Radial_102.ggr | 9 + krita/data/gradients/Flare_Radial_103.ggr | 4 + krita/data/gradients/Flare_Rays_Radial_1.ggr | 5 + krita/data/gradients/Flare_Rays_Radial_2.ggr | 5 + krita/data/gradients/Flare_Rays_Size_1.ggr | 19 + krita/data/gradients/Flare_Sizefac_101.ggr | 4 + krita/data/gradients/Four_bars.ggr | 11 + krita/data/gradients/French_flag.ggr | 6 + krita/data/gradients/French_flag_smooth.ggr | 5 + .../gradients/Full_saturation_spectrum_CCW.ggr | 4 + .../data/gradients/Full_saturation_spectrum_CW.ggr | 4 + krita/data/gradients/German_flag.ggr | 6 + krita/data/gradients/German_flag_smooth.ggr | 5 + krita/data/gradients/Golden.ggr | 17 + krita/data/gradients/Greens.ggr | 12 + krita/data/gradients/Horizon_1.ggr | 8 + krita/data/gradients/Horizon_2.ggr | 8 + krita/data/gradients/Incandescent.ggr | 7 + krita/data/gradients/Land_1.ggr | 8 + krita/data/gradients/Land_and_Sea.ggr | 8 + krita/data/gradients/Makefile.am | 4 + krita/data/gradients/Metallic_Something.ggr | 11 + krita/data/gradients/Mexican_flag.ggr | 6 + krita/data/gradients/Mexican_flag_smooth.ggr | 5 + krita/data/gradients/Nauseating_Headache.ggr | 28 + krita/data/gradients/Neon_Cyan.ggr | 7 + krita/data/gradients/Neon_Green.ggr | 7 + krita/data/gradients/Neon_Yellow.ggr | 7 + krita/data/gradients/Pastel_Rainbow.ggr | 4 + krita/data/gradients/Pastels.ggr | 17 + krita/data/gradients/Purples.ggr | 10 + krita/data/gradients/Radial_Eyeball_Blue.ggr | 8 + krita/data/gradients/Radial_Eyeball_Brown.ggr | 8 + krita/data/gradients/Radial_Eyeball_Green.ggr | 8 + krita/data/gradients/Radial_Glow_1.ggr | 8 + krita/data/gradients/Radial_Rainbow_Hoop.ggr | 6 + krita/data/gradients/Romanian_flag.ggr | 6 + krita/data/gradients/Romanian_flag_smooth.ggr | 5 + krita/data/gradients/Rounded_edge.ggr | 10 + krita/data/gradients/Shadows_1.ggr | 8 + krita/data/gradients/Shadows_2.ggr | 8 + krita/data/gradients/Shadows_3.ggr | 9 + krita/data/gradients/Skyline.ggr | 8 + krita/data/gradients/Skyline_polluted.ggr | 8 + krita/data/gradients/Square_Wood_Frame.ggr | 9 + krita/data/gradients/Sunrise.ggr | 9 + krita/data/gradients/Three_bars_sin.ggr | 9 + krita/data/gradients/Tropical_Colors.ggr | 12 + krita/data/gradients/Tube_Red.ggr | 10 + krita/data/gradients/Wood_1.ggr | 6 + krita/data/gradients/Wood_2.ggr | 12 + krita/data/gradients/Yellow_Contrast.ggr | 10 + krita/data/gradients/Yellow_Orange.ggr | 5 + krita/data/images/Azay-Le-Rideau.jpg | Bin 0 -> 82588 bytes krita/data/images/Makefile.am | 6 + krita/data/images/WeyDesc.png | Bin 0 -> 1061517 bytes krita/data/images/evenings.jpg | Bin 0 -> 53508 bytes krita/data/images/hakonepa.jpg | Bin 0 -> 58723 bytes krita/data/images/hiro_awate.jpg | Bin 0 -> 54282 bytes krita/data/images/paintbrush.png | Bin 0 -> 13185 bytes krita/data/images/previewfilter.png | Bin 0 -> 5987 bytes krita/data/krita_filter.desktop | 47 + krita/data/krita_paintop.desktop | 41 + krita/data/krita_plugin.desktop | 42 + krita/data/krita_tool.desktop | 46 + krita/data/palettes/40_Colors.gpl | 43 + krita/data/palettes/Anchor.gpl | 448 + krita/data/palettes/Bears.gpl | 259 + krita/data/palettes/Bgold.gpl | 259 + krita/data/palettes/Blues.gpl | 261 + krita/data/palettes/Borders.gpl | 259 + krita/data/palettes/Browns_And_Yellows.gpl | 25 + krita/data/palettes/Caramel.gpl | 259 + krita/data/palettes/Cascade.gpl | 259 + krita/data/palettes/China.gpl | 259 + krita/data/palettes/Coldfire.gpl | 259 + krita/data/palettes/Cool_Colors.gpl | 11 + krita/data/palettes/Cranes.gpl | 259 + krita/data/palettes/DMC.gpl | 458 + krita/data/palettes/Dark_pastels.gpl | 259 + krita/data/palettes/Default.gpl | 26 + krita/data/palettes/Ega.gpl | 244 + krita/data/palettes/Firecode.gpl | 259 + krita/data/palettes/Gold.gpl | 259 + krita/data/palettes/GrayViolet.gpl | 259 + krita/data/palettes/Grayblue.gpl | 259 + krita/data/palettes/Grays.gpl | 34 + krita/data/palettes/Greens.gpl | 259 + krita/data/palettes/Hilite.gpl | 259 + krita/data/palettes/Khaki.gpl | 258 + krita/data/palettes/Lights.gpl | 28 + krita/data/palettes/Madeira.gpl | 372 + krita/data/palettes/Makefile.am | 50 + krita/data/palettes/Muted.gpl | 81 + krita/data/palettes/Named_Colors.gpl | 452 + krita/data/palettes/News3.gpl | 259 + krita/data/palettes/Op2.gpl | 259 + krita/data/palettes/Paintjet.gpl | 22 + krita/data/palettes/Pantone_Coated_Approx.gpl | 949 + krita/data/palettes/Pastels.gpl | 21 + krita/data/palettes/Plasma.gpl | 260 + krita/data/palettes/Reds.gpl | 259 + krita/data/palettes/Reds_And_Purples.gpl | 33 + krita/data/palettes/Royal.gpl | 259 + krita/data/palettes/Topographic.gpl | 265 + krita/data/palettes/Visibone.gpl | 346 + krita/data/palettes/Visibone_2.gpl | 266 + krita/data/palettes/Volcano.gpl | 259 + krita/data/palettes/Warm_Colors.gpl | 10 + krita/data/palettes/Web.gpl | 220 + krita/data/palettes/new_kde.gpl | 48 + krita/data/patterns/3dgreen.pat | Bin 0 -> 6108 bytes krita/data/patterns/Craters.pat | Bin 0 -> 39707 bytes krita/data/patterns/Makefile.am | 5 + krita/data/patterns/Moonfoot.pat | Bin 0 -> 14442 bytes krita/data/patterns/Stripes1px.pat | Bin 0 -> 9253 bytes krita/data/patterns/Stripes2px.pat | Bin 0 -> 9248 bytes krita/data/patterns/amethyst.pat | Bin 0 -> 12321 bytes krita/data/patterns/bark.pat | Bin 0 -> 22173 bytes krita/data/patterns/blue.pat | Bin 0 -> 6108 bytes krita/data/patterns/bluegrid.pat | Bin 0 -> 1909 bytes krita/data/patterns/bluesquares.pat | Bin 0 -> 48037 bytes krita/data/patterns/blueweb.pat | Bin 0 -> 12321 bytes krita/data/patterns/brick.pat | Bin 0 -> 27674 bytes krita/data/patterns/burlap.pat | Bin 0 -> 27676 bytes krita/data/patterns/burlwood.pat | Bin 0 -> 27681 bytes krita/data/patterns/choc_swirl.pat | Bin 0 -> 7538 bytes krita/data/patterns/corkboard.pat | Bin 0 -> 10097 bytes krita/data/patterns/cracked.pat | Bin 0 -> 62238 bytes krita/data/patterns/crinklepaper.pat | Bin 0 -> 49191 bytes krita/data/patterns/electric.pat | Bin 0 -> 9638 bytes krita/data/patterns/fibers.pat | Bin 0 -> 7531 bytes krita/data/patterns/granite1.pat | Bin 0 -> 10035 bytes krita/data/patterns/ground1.pat | Bin 0 -> 30034 bytes krita/data/patterns/ice.pat | Bin 0 -> 43228 bytes krita/data/patterns/java.pat | Bin 0 -> 12315 bytes krita/data/patterns/leather.pat | Bin 0 -> 12320 bytes krita/data/patterns/leaves.pat | Bin 0 -> 7537 bytes krita/data/patterns/leopard.pat | Bin 0 -> 11921 bytes krita/data/patterns/lightning.pat | Bin 0 -> 40707 bytes krita/data/patterns/marble1.pat | Bin 0 -> 16418 bytes krita/data/patterns/marble2.pat | Bin 0 -> 16418 bytes krita/data/patterns/marble3.pat | Bin 0 -> 12322 bytes krita/data/patterns/nops.pat | Bin 0 -> 49178 bytes krita/data/patterns/paper.pat | Bin 0 -> 10030 bytes krita/data/patterns/parque1.pat | Bin 0 -> 12322 bytes krita/data/patterns/parque2.pat | Bin 0 -> 12322 bytes krita/data/patterns/parque3.pat | Bin 0 -> 12322 bytes krita/data/patterns/pastel.pat | Bin 0 -> 12325 bytes krita/data/patterns/pine.pat | Bin 0 -> 10781 bytes krita/data/patterns/pink_marble.pat | Bin 0 -> 49188 bytes krita/data/patterns/pool.pat | Bin 0 -> 6111 bytes krita/data/patterns/qube1.pat | Bin 0 -> 5331 bytes krita/data/patterns/rain.pat | Bin 0 -> 35021 bytes krita/data/patterns/recessed.pat | Bin 0 -> 6433 bytes krita/data/patterns/redcube.pat | Bin 0 -> 12320 bytes krita/data/patterns/rock.pat | Bin 0 -> 30510 bytes krita/data/patterns/sky.pat | Bin 0 -> 11002 bytes krita/data/patterns/slate.pat | Bin 0 -> 16414 bytes krita/data/patterns/sm_squares.pat | Bin 0 -> 7538 bytes krita/data/patterns/starfield.pat | Bin 0 -> 49163 bytes krita/data/patterns/stone33.pat | Bin 0 -> 73034 bytes krita/data/patterns/terra.pat | Bin 0 -> 12318 bytes krita/data/patterns/walnut.pat | Bin 0 -> 49183 bytes krita/data/patterns/warning.pat | Bin 0 -> 1233 bytes krita/data/patterns/wood1.pat | Bin 0 -> 27690 bytes krita/data/patterns/wood2.pat | Bin 0 -> 30030 bytes krita/data/patterns/wood3.pat | Bin 0 -> 7532 bytes krita/data/patterns/wood4.pat | Bin 0 -> 7532 bytes krita/data/patterns/wood5.pat | Bin 0 -> 27677 bytes krita/data/profiles/Adobe.icm | Bin 0 -> 2036 bytes krita/data/profiles/Apple.icm | Bin 0 -> 2036 bytes krita/data/profiles/CIE.icm | Bin 0 -> 2036 bytes krita/data/profiles/CMY.icm | Bin 0 -> 101936 bytes krita/data/profiles/ColorMatch.icm | Bin 0 -> 2044 bytes krita/data/profiles/Makefile.am | 4 + krita/data/profiles/NTSC.icm | Bin 0 -> 2044 bytes krita/data/profiles/PAL.icm | Bin 0 -> 2040 bytes krita/data/profiles/README | 5 + krita/data/profiles/SMPTE-C.icm | Bin 0 -> 2052 bytes krita/data/profiles/WideGamut.icm | Bin 0 -> 2044 bytes krita/data/profiles/cmyk.icm | Bin 0 -> 725408 bytes krita/data/profiles/fogra27l.icm | Bin 0 -> 225824 bytes krita/data/profiles/lcmslabi.icm | Bin 0 -> 154326 bytes krita/data/profiles/lcmsxyzi.icm | Bin 0 -> 154323 bytes krita/data/profiles/monoscnr.icm | Bin 0 -> 410 bytes krita/data/profiles/sRGB.icm | Bin 0 -> 2032 bytes krita/data/profiles/srgb_color_space_profile.icm | Bin 0 -> 3144 bytes krita/data/profiles/srgbspac.icm | Bin 0 -> 28202 bytes krita/data/profiles/tifflab8spac.icm | Bin 0 -> 200182 bytes krita/data/profiles/ycc601.icm | Bin 0 -> 101940 bytes krita/data/profiles/ycc709.icm | Bin 0 -> 101940 bytes krita/data/templates/.directory | 56 + krita/design.h | 27 + krita/doc/DESIGN.obsolete | 179 + krita/doc/Developing Krita Plugins.odt | Bin 0 -> 50195 bytes krita/doc/autoextending paintdevices | 54 + krita/doc/background_paper.txt | 84 + krita/doc/brush.txt | 36 + krita/doc/channels_masks_selections | 12 + krita/doc/colordiff | 68 + krita/doc/colorspaces.xmi | 41965 ++++++++++++++ krita/doc/colorstrategyAPI | 58 + krita/doc/controller.xmi | 39776 +++++++++++++ krita/doc/coordinates.txt | 9 + krita/doc/dirty.txt | 53 + krita/doc/doc-outline | 187 + krita/doc/histograms.xmi | 4145 ++ krita/doc/hooks | 33 + krita/doc/howtofilters.txt | 30 + krita/doc/impexp.txt | 41 + krita/doc/krita-features | 215 + krita/doc/krita.kpr | Bin 0 -> 2857392 bytes krita/doc/krita.pdf | Bin 0 -> 2701148 bytes krita/doc/krita.xmi | 56432 +++++++++++++++++++ krita/doc/large_files | 36 + krita/doc/layersupdatesignals.flw | Bin 0 -> 10783 bytes krita/doc/manual/krita.kwd | Bin 0 -> 2505240 bytes krita/doc/oasis | 5 + krita/doc/paint_device.txt | 98 + krita/doc/palettedesign.txt | 34 + krita/doc/plugins.txt | 32 + krita/doc/profiles.txt | 125 + krita/doc/resolution.txt | 40 + krita/doc/scripts/dcop.py | 14 + krita/doc/sdk | 10 + krita/doc/selections | 127 + krita/doc/the preview widget | 81 + krita/doc/transform_undo.txt | 38 + krita/dtd/Makefile.am | 4 + krita/dtd/krita.dtd | 93 + krita/extracti18n.pl | 90 + krita/krita.desktop | 95 + krita/krita.rc | 199 + krita/krita_part_init.cc | 23 + krita/krita_readonly.rc | 35 + krita/kritacolor/Makefile.am | 45 + krita/kritacolor/README | 4 + krita/kritacolor/TODO | 11 + krita/kritacolor/colorspaces/Makefile.am | 20 + .../kritacolor/colorspaces/kis_alpha_colorspace.cc | 296 + .../kritacolor/colorspaces/kis_alpha_colorspace.h | 93 + krita/kritacolor/colorspaces/kis_lab_colorspace.cc | 571 + krita/kritacolor/colorspaces/kis_lab_colorspace.h | 153 + krita/kritacolor/colorspaces/kis_xyz_colorspace.cc | 624 + krita/kritacolor/colorspaces/kis_xyz_colorspace.h | 112 + krita/kritacolor/kis_abstract_colorspace.cc | 762 + krita/kritacolor/kis_abstract_colorspace.h | 312 + krita/kritacolor/kis_basic_histogram_producers.cc | 484 + krita/kritacolor/kis_basic_histogram_producers.h | 197 + krita/kritacolor/kis_channelinfo.h | 115 + krita/kritacolor/kis_color.cc | 185 + krita/kritacolor/kis_color.h | 90 + krita/kritacolor/kis_color_conversions.cc | 427 + krita/kritacolor/kis_color_conversions.h | 49 + krita/kritacolor/kis_colorspace.cc | 39 + krita/kritacolor/kis_colorspace.h | 450 + .../kritacolor/kis_colorspace_factory_registry.cc | 222 + krita/kritacolor/kis_colorspace_factory_registry.h | 120 + krita/kritacolor/kis_colorspace_iface.cc | 39 + krita/kritacolor/kis_colorspace_iface.h | 43 + krita/kritacolor/kis_composite_op.cc | 138 + krita/kritacolor/kis_composite_op.h | 103 + krita/kritacolor/kis_f16half_base_colorspace.cc | 125 + krita/kritacolor/kis_f16half_base_colorspace.h | 107 + krita/kritacolor/kis_f32_base_colorspace.cc | 125 + krita/kritacolor/kis_f32_base_colorspace.h | 83 + krita/kritacolor/kis_histogram_producer.cc | 67 + krita/kritacolor/kis_histogram_producer.h | 129 + krita/kritacolor/kis_profile.cc | 208 + krita/kritacolor/kis_profile.h | 98 + krita/kritacolor/kis_u16_base_colorspace.cc | 148 + krita/kritacolor/kis_u16_base_colorspace.h | 80 + krita/kritacolor/kis_u8_base_colorspace.cc | 118 + krita/kritacolor/kis_u8_base_colorspace.h | 77 + krita/kritacolor/krita_colorspace.desktop | 38 + krita/kritacolor/tests/Makefile.am | 16 + .../tests/kis_color_conversions_tester.cpp | 227 + .../tests/kis_color_conversions_tester.h | 44 + krita/kritapart.desktop | 91 + krita/main.cc | 43 + krita/pics/Makefile.am | 22 + krita/pics/deletelayer.png | Bin 0 -> 375 bytes krita/pics/height.png | Bin 0 -> 201 bytes krita/pics/hi128-app-krita.png | Bin 0 -> 9548 bytes krita/pics/hi16-app-krita.png | Bin 0 -> 637 bytes krita/pics/hi22-app-krita.png | Bin 0 -> 929 bytes krita/pics/hi32-app-krita.png | Bin 0 -> 1486 bytes krita/pics/hi48-app-krita.png | Bin 0 -> 2586 bytes krita/pics/hi64-app-krita.png | Bin 0 -> 3835 bytes krita/pics/krita.svg | 509 + krita/pics/linked.png | Bin 0 -> 527 bytes krita/pics/locked.png | Bin 0 -> 556 bytes krita/pics/lowerlayer.png | Bin 0 -> 362 bytes krita/pics/newlayer.png | Bin 0 -> 425 bytes krita/pics/novisible.png | Bin 0 -> 720 bytes krita/pics/raiselayer.png | Bin 0 -> 343 bytes krita/pics/shade.png | Bin 0 -> 234 bytes krita/pics/tablet.png | Bin 0 -> 4452 bytes krita/pics/tool_screenshot.png | Bin 0 -> 851 bytes krita/pics/unlinked.png | Bin 0 -> 362 bytes krita/pics/unlocked.png | Bin 0 -> 604 bytes krita/pics/visible.png | Bin 0 -> 770 bytes krita/pics/width.png | Bin 0 -> 178 bytes krita/plugins/Makefile.am | 5 + krita/plugins/README | 42 + krita/plugins/configure.in.in | 2 + krita/plugins/filters/Makefile.am | 4 + krita/plugins/filters/blur/Makefile.am | 21 + krita/plugins/filters/blur/blur.cc | 50 + krita/plugins/filters/blur/blur.h | 37 + krita/plugins/filters/blur/kis_blur_filter.cc | 143 + krita/plugins/filters/blur/kis_blur_filter.h | 49 + krita/plugins/filters/blur/kis_wdg_blur.cc | 116 + krita/plugins/filters/blur/kis_wdg_blur.h | 49 + krita/plugins/filters/blur/kritablurfilter.desktop | 38 + krita/plugins/filters/blur/wdgblur.ui | 227 + krita/plugins/filters/bumpmap/Makefile.am | 18 + krita/plugins/filters/bumpmap/bumpmap.cc | 533 + krita/plugins/filters/bumpmap/bumpmap.h | 129 + .../filters/bumpmap/kritabumpmapfilter.desktop | 71 + krita/plugins/filters/bumpmap/wdgbumpmap.ui | 374 + krita/plugins/filters/cimg/.kdev_ignore | 0 krita/plugins/filters/cimg/CImg.h | 19174 +++++++ krita/plugins/filters/cimg/Makefile.am | 34 + krita/plugins/filters/cimg/kis_cimg_filter.cc | 711 + krita/plugins/filters/cimg/kis_cimg_filter.h | 124 + krita/plugins/filters/cimg/kis_cimg_plugin.cc | 44 + krita/plugins/filters/cimg/kis_cimg_plugin.h | 32 + .../plugins/filters/cimg/kis_cimgconfig_widget.cc | 94 + krita/plugins/filters/cimg/kis_cimgconfig_widget.h | 49 + krita/plugins/filters/cimg/kritacimg.desktop | 79 + krita/plugins/filters/cimg/wdg_cimg.ui | 298 + krita/plugins/filters/colorify/Colorify.cpp | 122 + krita/plugins/filters/colorify/Colorify.h | 56 + krita/plugins/filters/colorify/KisWdgColorify.cpp | 50 + krita/plugins/filters/colorify/KisWdgColorify.h | 44 + krita/plugins/filters/colorify/Makefile.am | 22 + krita/plugins/filters/colorify/WdgColorifyBase.ui | 97 + .../filters/colorify/kritacolorifyfilter.desktop | 42 + krita/plugins/filters/colors/Makefile.am | 20 + krita/plugins/filters/colors/colors.cc | 53 + krita/plugins/filters/colors/colors.h | 37 + krita/plugins/filters/colors/kis_color_to_alpha.cc | 95 + krita/plugins/filters/colors/kis_color_to_alpha.h | 47 + krita/plugins/filters/colors/kis_minmax_filters.cc | 162 + krita/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 | 44 + .../colors/kritaextensioncolorsfilters.desktop | 42 + .../plugins/filters/colors/wdgcolortoalphabase.ui | 113 + krita/plugins/filters/colorsfilters/Makefile.am | 25 + .../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 | 99 + .../colorsfilters/kritacolorsfilter.desktop | 94 + .../colorsfilters/wdg_brightness_contrast.ui | 292 + .../filters/colorsfilters/wdg_perchannel.ui | 190 + .../plugins/filters/convolutionfilters/Makefile.am | 27 + .../convolutionfilters/convolutionfilters.cc | 176 + .../convolutionfilters/convolutionfilters.h | 152 + .../convolutionfilters/kis_convolution_filter.cc | 138 + .../convolutionfilters/kis_convolution_filter.h | 98 + .../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 | 45 + .../kritaconvolutionfilters.desktop | 75 + krita/plugins/filters/cubismfilter/Makefile.am | 24 + .../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 + krita/plugins/filters/cubismfilter/kis_polygon.cc | 102 + krita/plugins/filters/cubismfilter/kis_polygon.h | 37 + .../filters/cubismfilter/kritacubismfilter.desktop | 85 + krita/plugins/filters/embossfilter/Makefile.am | 23 + .../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 + .../filters/embossfilter/kritaembossfilter.desktop | 71 + krita/plugins/filters/example/Makefile.am | 21 + krita/plugins/filters/example/example.cc | 95 + krita/plugins/filters/example/example.h | 47 + krita/plugins/filters/example/kritaexample.desktop | 81 + .../plugins/filters/fastcolortransfer/Makefile.am | 22 + .../filters/fastcolortransfer/fastcolortransfer.cc | 206 + .../filters/fastcolortransfer/fastcolortransfer.h | 55 + .../kis_wdg_fastcolortransfer.cpp | 50 + .../fastcolortransfer/kis_wdg_fastcolortransfer.h | 47 + .../kritafastcolortransfer.desktop | 69 + .../fastcolortransfer/wdgfastcolortransfer.ui | 75 + krita/plugins/filters/halftone/kis_halftone.cpp | 190 + krita/plugins/filters/halftone/kis_halftone.h | 79 + krita/plugins/filters/imageenhancement/Makefile.am | 26 + .../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 + .../imageenhancement/kritaimageenhancement.desktop | 80 + .../filters/lenscorrectionfilter/Makefile.am | 22 + .../kis_wdg_lens_correction.cpp | 74 + .../lenscorrectionfilter/kis_wdg_lens_correction.h | 43 + .../kritalenscorrectionfilter.desktop | 69 + .../lenscorrectionfilter/lenscorrectionfilter.cc | 152 + .../lenscorrectionfilter/lenscorrectionfilter.h | 53 + .../wdglenscorrectionoptions.ui | 229 + krita/plugins/filters/levelfilter/Makefile.am | 24 + .../plugins/filters/levelfilter/kgradientslider.cc | 338 + .../plugins/filters/levelfilter/kgradientslider.h | 84 + .../filters/levelfilter/kis_level_filter.cc | 324 + .../plugins/filters/levelfilter/kis_level_filter.h | 93 + .../filters/levelfilter/kritalevelfilter.desktop | 73 + krita/plugins/filters/levelfilter/levelfilter.cc | 67 + krita/plugins/filters/levelfilter/levelfilter.h | 35 + krita/plugins/filters/levelfilter/wdg_level.ui | 331 + krita/plugins/filters/noisefilter/Makefile.am | 22 + .../plugins/filters/noisefilter/kis_wdg_noise.cpp | 59 + krita/plugins/filters/noisefilter/kis_wdg_noise.h | 43 + .../filters/noisefilter/kritanoisefilter.desktop | 77 + krita/plugins/filters/noisefilter/noisefilter.cc | 128 + krita/plugins/filters/noisefilter/noisefilter.h | 52 + .../plugins/filters/noisefilter/wdgnoiseoptions.ui | 111 + krita/plugins/filters/oilpaintfilter/Makefile.am | 23 + .../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 + .../oilpaintfilter/kritaoilpaintfilter.desktop | 77 + krita/plugins/filters/pixelizefilter/Makefile.am | 23 + .../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 + .../pixelizefilter/kritapixelizefilter.desktop | 83 + krita/plugins/filters/raindropsfilter/Makefile.am | 23 + .../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 + .../raindropsfilter/kritaraindropsfilter.desktop | 81 + krita/plugins/filters/randompickfilter/Makefile.am | 22 + .../randompickfilter/kis_wdg_random_pick.cpp | 64 + .../filters/randompickfilter/kis_wdg_random_pick.h | 43 + .../randompickfilter/kritarandompickfilter.desktop | 65 + .../filters/randompickfilter/randompickfilter.cc | 131 + .../filters/randompickfilter/randompickfilter.h | 52 + .../randompickfilter/wdgrandompickoptions.ui | 135 + krita/plugins/filters/roundcorners/Makefile.am | 22 + .../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 + .../roundcorners/kritaroundcornersfilter.desktop | 39 + krita/plugins/filters/smalltilesfilter/Makefile.am | 22 + .../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 + .../smalltilesfilter/kritasmalltilesfilter.desktop | 39 + krita/plugins/filters/sobelfilter/Makefile.am | 22 + .../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 + .../filters/sobelfilter/kritasobelfilter.desktop | 39 + krita/plugins/filters/threadtest/Makefile.am | 18 + .../filters/threadtest/kritathreadtest.desktop | 38 + krita/plugins/filters/threadtest/threadtest.cc | 140 + krita/plugins/filters/threadtest/threadtest.h | 46 + krita/plugins/filters/unsharp/Makefile.am | 19 + .../plugins/filters/unsharp/kis_unsharp_filter.cc | 152 + krita/plugins/filters/unsharp/kis_unsharp_filter.h | 47 + krita/plugins/filters/unsharp/kis_wdg_unsharp.cc | 52 + krita/plugins/filters/unsharp/kis_wdg_unsharp.h | 44 + .../filters/unsharp/kritaunsharpfilter.desktop | 40 + krita/plugins/filters/unsharp/unsharp.cc | 50 + krita/plugins/filters/unsharp/unsharp.h | 37 + krita/plugins/filters/unsharp/wdgunsharp.ui | 138 + krita/plugins/filters/wavefilter/Makefile.am | 22 + krita/plugins/filters/wavefilter/kis_wdg_wave.cpp | 90 + krita/plugins/filters/wavefilter/kis_wdg_wave.h | 43 + .../filters/wavefilter/kritawavefilter.desktop | 72 + krita/plugins/filters/wavefilter/wavefilter.cc | 169 + krita/plugins/filters/wavefilter/wavefilter.h | 53 + krita/plugins/filters/wavefilter/wdgwaveoptions.ui | 281 + krita/plugins/paintops/Makefile.am | 2 + krita/plugins/paintops/defaultpaintops/Makefile.am | 38 + krita/plugins/paintops/defaultpaintops/README | 3 + .../plugins/paintops/defaultpaintops/airbrush.png | Bin 0 -> 1037 bytes .../defaultpaintops/defaultpaintops_plugin.cc | 70 + .../defaultpaintops/defaultpaintops_plugin.h | 35 + krita/plugins/paintops/defaultpaintops/eraser.png | Bin 0 -> 734 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 | 112 + .../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 + krita/plugins/paintops/defaultpaintops/kis_penop.h | 58 + .../paintops/defaultpaintops/kis_smudgeop.cc | 328 + .../paintops/defaultpaintops/kis_smudgeop.h | 117 + .../defaultpaintops/kritadefaultpaintops.desktop | 93 + .../paintops/defaultpaintops/paintbrush.png | Bin 0 -> 769 bytes krita/plugins/paintops/defaultpaintops/pencil.png | Bin 0 -> 793 bytes krita/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 + krita/plugins/tools/Makefile.am | 3 + krita/plugins/tools/defaulttools/Makefile.am | 82 + .../tools/defaulttools/closedhand_cursor.xpm | 28 + krita/plugins/tools/defaulttools/default_tools.cc | 88 + krita/plugins/tools/defaulttools/default_tools.h | 43 + krita/plugins/tools/defaulttools/kis_tool_brush.cc | 167 + krita/plugins/tools/defaulttools/kis_tool_brush.h | 86 + .../tools/defaulttools/kis_tool_colorpicker.cc | 298 + .../tools/defaulttools/kis_tool_colorpicker.h | 87 + .../tools/defaulttools/kis_tool_duplicate.cc | 255 + .../tools/defaulttools/kis_tool_duplicate.h | 91 + .../plugins/tools/defaulttools/kis_tool_ellipse.cc | 186 + .../plugins/tools/defaulttools/kis_tool_ellipse.h | 90 + krita/plugins/tools/defaulttools/kis_tool_fill.cc | 233 + krita/plugins/tools/defaulttools/kis_tool_fill.h | 108 + .../tools/defaulttools/kis_tool_gradient.cc | 309 + .../plugins/tools/defaulttools/kis_tool_gradient.h | 123 + krita/plugins/tools/defaulttools/kis_tool_line.cc | 254 + krita/plugins/tools/defaulttools/kis_tool_line.h | 99 + krita/plugins/tools/defaulttools/kis_tool_move.cc | 181 + krita/plugins/tools/defaulttools/kis_tool_move.h | 88 + krita/plugins/tools/defaulttools/kis_tool_pan.cc | 96 + krita/plugins/tools/defaulttools/kis_tool_pan.h | 79 + .../tools/defaulttools/kis_tool_rectangle.cc | 187 + .../tools/defaulttools/kis_tool_rectangle.h | 95 + krita/plugins/tools/defaulttools/kis_tool_text.cc | 198 + krita/plugins/tools/defaulttools/kis_tool_text.h | 80 + krita/plugins/tools/defaulttools/kis_tool_zoom.cc | 191 + krita/plugins/tools/defaulttools/kis_tool_zoom.h | 97 + .../tools/defaulttools/kritadefaulttools.desktop | 56 + .../plugins/tools/defaulttools/openhand_cursor.xpm | 28 + .../plugins/tools/defaulttools/tool_color_fill.png | Bin 0 -> 1101 bytes .../tools/defaulttools/tool_colorpicker.png | Bin 0 -> 711 bytes .../plugins/tools/defaulttools/tool_duplicate.png | Bin 0 -> 1086 bytes .../tools/defaulttools/tool_duplicate_cursor.png | Bin 0 -> 308 bytes krita/plugins/tools/defaulttools/tool_ellipse.png | Bin 0 -> 523 bytes .../tools/defaulttools/tool_ellipse_cursor.png | Bin 0 -> 308 bytes .../tools/defaulttools/tool_fill_cursor.png | Bin 0 -> 515 bytes krita/plugins/tools/defaulttools/tool_freehand.png | Bin 0 -> 657 bytes .../tools/defaulttools/tool_freehand_cursor.png | Bin 0 -> 260 bytes krita/plugins/tools/defaulttools/tool_gradient.png | Bin 0 -> 385 bytes .../tools/defaulttools/tool_gradient_cursor.png | Bin 0 -> 293 bytes krita/plugins/tools/defaulttools/tool_line.png | Bin 0 -> 353 bytes .../tools/defaulttools/tool_line_cursor.png | Bin 0 -> 247 bytes krita/plugins/tools/defaulttools/tool_move.png | Bin 0 -> 662 bytes krita/plugins/tools/defaulttools/tool_pan.png | Bin 0 -> 862 bytes .../plugins/tools/defaulttools/tool_rectangle.png | Bin 0 -> 333 bytes .../tools/defaulttools/tool_rectangle_cursor.png | Bin 0 -> 229 bytes krita/plugins/tools/defaulttools/tool_text.png | Bin 0 -> 890 bytes .../tools/defaulttools/tool_text_cursor.png | Bin 0 -> 299 bytes krita/plugins/tools/defaulttools/tool_zoom.png | Bin 0 -> 876 bytes .../tools/defaulttools/tool_zoom_minus_cursor.png | Bin 0 -> 282 bytes .../tools/defaulttools/tool_zoom_plus_cursor.png | Bin 0 -> 301 bytes krita/plugins/tools/defaulttools/wdgcolorpicker.ui | 167 + krita/plugins/tools/selectiontools/Makefile.am | 55 + .../selectiontools/kis_tool_move_selection.cc | 223 + .../tools/selectiontools/kis_tool_move_selection.h | 74 + .../tools/selectiontools/kis_tool_select_brush.cc | 168 + .../tools/selectiontools/kis_tool_select_brush.h | 82 + .../selectiontools/kis_tool_select_contiguous.cc | 234 + .../selectiontools/kis_tool_select_contiguous.h | 94 + .../selectiontools/kis_tool_select_elliptical.cc | 321 + .../selectiontools/kis_tool_select_elliptical.h | 98 + .../tools/selectiontools/kis_tool_select_eraser.cc | 156 + .../tools/selectiontools/kis_tool_select_eraser.h | 81 + .../selectiontools/kis_tool_select_outline.cc | 295 + .../tools/selectiontools/kis_tool_select_outline.h | 100 + .../selectiontools/kis_tool_select_polygonal.cc | 315 + .../selectiontools/kis_tool_select_polygonal.h | 105 + .../selectiontools/kis_tool_select_rectangular.cc | 323 + .../selectiontools/kis_tool_select_rectangular.h | 94 + .../selectiontools/kritaselectiontools.desktop | 52 + .../tools/selectiontools/selection_tools.cc | 77 + .../plugins/tools/selectiontools/selection_tools.h | 43 + .../tools/selectiontools/tool_brush_selection.png | Bin 0 -> 1051 bytes .../tools/selectiontools/tool_brush_selection.svg | 827 + .../selectiontools/tool_brush_selection_cursor.png | Bin 0 -> 338 bytes .../selectiontools/tool_contiguous_selection.png | Bin 0 -> 835 bytes .../tool_contiguous_selection_cursor.png | Bin 0 -> 320 bytes .../selectiontools/tool_elliptical_selection.png | Bin 0 -> 702 bytes .../selectiontools/tool_elliptical_selection.svg | 256 + .../tool_elliptical_selection_cursor.png | Bin 0 -> 295 bytes .../tools/selectiontools/tool_eraser_selection.png | Bin 0 -> 1086 bytes .../tools/selectiontools/tool_eraser_selection.svg | 1993 + .../tool_eraser_selection_cursor.png | Bin 0 -> 340 bytes .../selectiontools/tool_outline_selection.png | Bin 0 -> 555 bytes .../selectiontools/tool_outline_selection.svg | 329 + .../tool_outline_selection_cursor.png | Bin 0 -> 358 bytes .../selectiontools/tool_polygonal_selection.png | Bin 0 -> 575 bytes .../selectiontools/tool_polygonal_selection.svg | 364 + .../tool_polygonal_selection_cursor.png | Bin 0 -> 432 bytes .../tools/selectiontools/tool_rect_selection.png | Bin 0 -> 522 bytes .../tools/selectiontools/tool_rect_selection.svg | 191 + .../tool_rectangular_selection_cursor.png | Bin 0 -> 223 bytes krita/plugins/tools/tool_crop/Makefile.am | 36 + krita/plugins/tools/tool_crop/kis_tool_crop.cc | 925 + krita/plugins/tools/tool_crop/kis_tool_crop.h | 148 + .../plugins/tools/tool_crop/kritatoolcrop.desktop | 47 + krita/plugins/tools/tool_crop/tool_crop.cc | 62 + krita/plugins/tools/tool_crop/tool_crop.h | 42 + krita/plugins/tools/tool_crop/tool_crop.png | Bin 0 -> 692 bytes krita/plugins/tools/tool_crop/tool_crop_cursor.png | Bin 0 -> 305 bytes krita/plugins/tools/tool_crop/wdg_tool_crop.ui | 216 + krita/plugins/tools/tool_curves/Makefile.am | 55 + .../tools/tool_curves/kis_curve_framework.cc | 260 + .../tools/tool_curves/kis_curve_framework.h | 354 + krita/plugins/tools/tool_curves/kis_tool_bezier.cc | 366 + krita/plugins/tools/tool_curves/kis_tool_bezier.h | 97 + .../tools/tool_curves/kis_tool_bezier_paint.cc | 115 + .../tools/tool_curves/kis_tool_bezier_paint.h | 62 + .../tools/tool_curves/kis_tool_bezier_select.cc | 104 + .../tools/tool_curves/kis_tool_bezier_select.h | 62 + krita/plugins/tools/tool_curves/kis_tool_curve.cc | 593 + krita/plugins/tools/tool_curves/kis_tool_curve.h | 204 + .../plugins/tools/tool_curves/kis_tool_example.cc | 108 + krita/plugins/tools/tool_curves/kis_tool_example.h | 66 + .../plugins/tools/tool_curves/kis_tool_moutline.cc | 809 + .../plugins/tools/tool_curves/kis_tool_moutline.h | 131 + .../tools/tool_curves/kritatoolcurves.desktop | 36 + .../tools/tool_curves/tool_bezier_cursor.png | Bin 0 -> 2853 bytes .../tools/tool_curves/tool_bezier_paint.png | Bin 0 -> 679 bytes .../tools/tool_curves/tool_bezier_select.png | Bin 0 -> 636 bytes .../tools/tool_curves/tool_curve_dragging.png | Bin 0 -> 2955 bytes krita/plugins/tools/tool_curves/tool_curves.cc | 67 + krita/plugins/tools/tool_curves/tool_curves.h | 35 + krita/plugins/tools/tool_curves/tool_example.png | Bin 0 -> 2917 bytes .../tools/tool_curves/tool_example_cursor.png | Bin 0 -> 2853 bytes krita/plugins/tools/tool_curves/tool_moutline.png | Bin 0 -> 777 bytes .../tools/tool_curves/tool_moutline_cursor.png | Bin 0 -> 2857 bytes .../tools/tool_curves/tool_moutline_editing.png | Bin 0 -> 2967 bytes .../plugins/tools/tool_curves/wdg_tool_example.ui | 128 + krita/plugins/tools/tool_filter/Makefile.am | 37 + krita/plugins/tools/tool_filter/kis_filterop.cc | 154 + krita/plugins/tools/tool_filter/kis_filterop.h | 63 + krita/plugins/tools/tool_filter/kis_tool_filter.cc | 154 + krita/plugins/tools/tool_filter/kis_tool_filter.h | 80 + .../tools/tool_filter/kritatoolfilter.desktop | 92 + krita/plugins/tools/tool_filter/tool_filter.cc | 68 + krita/plugins/tools/tool_filter/tool_filter.h | 42 + krita/plugins/tools/tool_filter/tool_filter.png | Bin 0 -> 496 bytes krita/plugins/tools/tool_filter/tool_filter.svg | 468 + .../tools/tool_filter/tool_filter_cursor.png | Bin 0 -> 294 bytes .../plugins/tools/tool_perspectivegrid/Makefile.am | 34 + .../kis_tool_perspectivegrid.cc | 499 + .../kis_tool_perspectivegrid.h | 110 + .../kritatoolperspectivegrid.desktop | 35 + .../tool_perspectivegrid/tool_perspectivegrid.cc | 62 + .../tool_perspectivegrid/tool_perspectivegrid.h | 42 + .../tool_perspectivegrid/tool_perspectivegrid.png | Bin 0 -> 737 bytes .../tool_perspectivegrid/tool_perspectivegrid.svg | 87 + .../tools/tool_perspectivetransform/Makefile.am | 34 + .../kis_tool_perspectivetransform.cc | 742 + .../kis_tool_perspectivetransform.h | 130 + .../kritatoolperspectivetransform.desktop | 37 + .../tool_perspectivetransform.cc | 63 + .../tool_perspectivetransform.h | 42 + .../tool_perspectivetransform.png | Bin 0 -> 690 bytes .../tool_perspectivetransform.svg | 87 + krita/plugins/tools/tool_polygon/Makefile.am | 35 + .../plugins/tools/tool_polygon/kis_tool_polygon.cc | 252 + .../plugins/tools/tool_polygon/kis_tool_polygon.h | 101 + .../tools/tool_polygon/kritatoolpolygon.desktop | 52 + krita/plugins/tools/tool_polygon/tool_polygon.cc | 62 + krita/plugins/tools/tool_polygon/tool_polygon.h | 38 + krita/plugins/tools/tool_polygon/tool_polygon.png | Bin 0 -> 772 bytes .../tools/tool_polygon/tool_polygon_cursor.png | Bin 0 -> 401 bytes krita/plugins/tools/tool_polyline/Makefile.am | 35 + .../tools/tool_polyline/kis_tool_polyline.cc | 271 + .../tools/tool_polyline/kis_tool_polyline.h | 108 + .../tools/tool_polyline/kritatoolpolyline.desktop | 49 + krita/plugins/tools/tool_polyline/polyline.png | Bin 0 -> 586 bytes krita/plugins/tools/tool_polyline/tool_polyline.cc | 64 + krita/plugins/tools/tool_polyline/tool_polyline.h | 42 + .../tools/tool_polyline/tool_polyline_cursor.png | Bin 0 -> 396 bytes krita/plugins/tools/tool_selectsimilar/Makefile.am | 31 + .../tool_selectsimilar/kis_tool_selectsimilar.cc | 271 + .../tool_selectsimilar/kis_tool_selectsimilar.h | 101 + .../kritatoolselectsimilar.desktop | 43 + .../tools/tool_selectsimilar/selectsimilar.cc | 61 + .../tools/tool_selectsimilar/selectsimilar.h | 34 + .../tool_selectsimilar/tool_similar_selection.png | Bin 0 -> 723 bytes .../tool_selectsimilar/tool_similar_selection.svg | 2118 + .../tool_similar_selection_minus_cursor.png | Bin 0 -> 612 bytes .../tool_similar_selection_plus_cursor.png | Bin 0 -> 629 bytes krita/plugins/tools/tool_star/Makefile.am | 36 + krita/plugins/tools/tool_star/kis_tool_star.cc | 245 + krita/plugins/tools/tool_star/kis_tool_star.h | 100 + .../plugins/tools/tool_star/kritatoolstar.desktop | 52 + krita/plugins/tools/tool_star/tool_star.cc | 62 + krita/plugins/tools/tool_star/tool_star.h | 42 + krita/plugins/tools/tool_star/tool_star.png | Bin 0 -> 624 bytes krita/plugins/tools/tool_star/tool_star_cursor.png | Bin 0 -> 366 bytes krita/plugins/tools/tool_star/wdg_tool_star.ui | 128 + krita/plugins/tools/tool_transform/Makefile.am | 36 + .../tools/tool_transform/kis_tool_transform.cc | 916 + .../tools/tool_transform/kis_tool_transform.h | 154 + .../tool_transform/kritatooltransform.desktop | 46 + .../plugins/tools/tool_transform/rotate_cursor.xpm | 29 + .../plugins/tools/tool_transform/tool_transform.cc | 64 + .../plugins/tools/tool_transform/tool_transform.h | 42 + .../tools/tool_transform/tool_transform.png | Bin 0 -> 457 bytes .../tools/tool_transform/wdg_tool_transform.ui | 243 + krita/plugins/viewplugins/Makefile.am | 24 + krita/plugins/viewplugins/colorrange/Makefile.am | 24 + krita/plugins/viewplugins/colorrange/colorrange.cc | 82 + krita/plugins/viewplugins/colorrange/colorrange.h | 44 + krita/plugins/viewplugins/colorrange/colorrange.rc | 10 + .../viewplugins/colorrange/dlg_colorrange.cc | 351 + .../viewplugins/colorrange/dlg_colorrange.h | 99 + .../viewplugins/colorrange/kritacolorrange.desktop | 40 + .../viewplugins/colorrange/wdg_colorrange.ui | 252 + .../viewplugins/colorspaceconversion/Makefile.am | 26 + .../colorspaceconversion/colorspaceconversion.cc | 155 + .../colorspaceconversion/colorspaceconversion.h | 50 + .../colorspaceconversion/colorspaceconversion.rc | 11 + .../dlg_colorspaceconversion.cc | 91 + .../dlg_colorspaceconversion.h | 49 + .../kritacolorspaceconversion.desktop | 40 + .../colorspaceconversion/wdgconvertcolorspace.ui | 218 + krita/plugins/viewplugins/dropshadow/Makefile.am | 30 + .../viewplugins/dropshadow/dlg_dropshadow.cc | 117 + .../viewplugins/dropshadow/dlg_dropshadow.h | 59 + krita/plugins/viewplugins/dropshadow/dropshadow.rc | 11 + .../viewplugins/dropshadow/kis_dropshadow.cc | 758 + .../viewplugins/dropshadow/kis_dropshadow.h | 71 + .../dropshadow/kis_dropshadow_plugin.cc | 91 + .../viewplugins/dropshadow/kis_dropshadow_plugin.h | 45 + .../viewplugins/dropshadow/kritadropshadow.desktop | 39 + .../viewplugins/dropshadow/wdg_dropshadow.ui | 235 + .../plugins/viewplugins/filtersgallery/Makefile.am | 25 + .../viewplugins/filtersgallery/filters_gallery.cc | 138 + .../viewplugins/filtersgallery/filters_gallery.h | 53 + .../filtersgallery/kis_dlg_filtersgallery.cc | 133 + .../filtersgallery/kis_dlg_filtersgallery.h | 68 + .../filtersgallery/kis_wdg_filtersgallery.ui | 123 + .../filtersgallery/kritafiltersgallery.desktop | 45 + .../filtersgallery/kritafiltersgallery.rc | 9 + krita/plugins/viewplugins/histogram/Makefile.am | 24 + .../plugins/viewplugins/histogram/dlg_histogram.cc | 68 + .../plugins/viewplugins/histogram/dlg_histogram.h | 57 + krita/plugins/viewplugins/histogram/histogram.cc | 105 + krita/plugins/viewplugins/histogram/histogram.h | 49 + krita/plugins/viewplugins/histogram/histogram.rc | 10 + .../viewplugins/histogram/kis_histogram_widget.cc | 147 + .../viewplugins/histogram/kis_histogram_widget.h | 54 + .../viewplugins/histogram/kritahistogram.desktop | 43 + .../plugins/viewplugins/histogram/wdghistogram.ui | 229 + .../viewplugins/histogram_docker/Makefile.am | 21 + .../histogram_docker/histogramdocker.cc | 192 + .../viewplugins/histogram_docker/histogramdocker.h | 79 + .../histogram_docker/kis_accumulating_producer.cc | 102 + .../histogram_docker/kis_accumulating_producer.h | 76 + .../histogram_docker/kis_cachedhistogram.cc | 37 + .../histogram_docker/kis_cachedhistogram.h | 53 + .../histogram_docker/kis_imagerasteredcache.cc | 162 + .../histogram_docker/kis_imagerasteredcache.h | 80 + .../histogram_docker/kritahistogramdocker.desktop | 40 + .../histogram_docker/kritahistogramdocker.rc | 3 + .../plugins/viewplugins/history_docker/Makefile.am | 18 + .../viewplugins/history_docker/historydocker.cc | 58 + .../viewplugins/history_docker/historydocker.h | 34 + .../history_docker/kritahistorydocker.desktop | 73 + krita/plugins/viewplugins/imagesize/Makefile.am | 24 + .../plugins/viewplugins/imagesize/configure.in.in | 1 + .../plugins/viewplugins/imagesize/dlg_imagesize.cc | 277 + .../plugins/viewplugins/imagesize/dlg_imagesize.h | 82 + .../plugins/viewplugins/imagesize/dlg_layersize.cc | 261 + .../plugins/viewplugins/imagesize/dlg_layersize.h | 73 + krita/plugins/viewplugins/imagesize/imagesize.cc | 190 + krita/plugins/viewplugins/imagesize/imagesize.h | 48 + krita/plugins/viewplugins/imagesize/imagesize.rc | 15 + .../viewplugins/imagesize/kritaimagesize.desktop | 39 + .../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 | 26 + .../modify_selection/dlg_border_selection.cc | 76 + .../modify_selection/dlg_border_selection.h | 48 + .../modify_selection/dlg_grow_selection.cc | 76 + .../modify_selection/dlg_grow_selection.h | 48 + .../modify_selection/dlg_shrink_selection.cc | 81 + .../modify_selection/dlg_shrink_selection.h | 49 + .../modify_selection/kritamodifyselection.desktop | 40 + .../modify_selection/modify_selection.cc | 158 + .../modify_selection/modify_selection.h | 46 + .../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 | 24 + .../viewplugins/performancetest/dlg_perftest.cc | 110 + .../viewplugins/performancetest/dlg_perftest.h | 55 + .../performancetest/kritaperftest.desktop | 41 + .../viewplugins/performancetest/perftest.cc | 1198 + .../plugins/viewplugins/performancetest/perftest.h | 75 + .../viewplugins/performancetest/perftest.rc | 9 + .../viewplugins/performancetest/wdg_perftest.ui | 283 + krita/plugins/viewplugins/rotateimage/Makefile.am | 24 + .../viewplugins/rotateimage/dlg_rotateimage.cc | 147 + .../viewplugins/rotateimage/dlg_rotateimage.h | 65 + .../rotateimage/kritarotateimage.desktop | 40 + .../plugins/viewplugins/rotateimage/rotateimage.cc | 134 + .../plugins/viewplugins/rotateimage/rotateimage.h | 49 + .../plugins/viewplugins/rotateimage/rotateimage.rc | 25 + .../viewplugins/rotateimage/wdg_rotateimage.ui | 245 + krita/plugins/viewplugins/screenshot/Makefile.am | 26 + .../viewplugins/screenshot/kritascreenshot.desktop | 47 + krita/plugins/viewplugins/screenshot/ksnapshot.cpp | 499 + krita/plugins/viewplugins/screenshot/ksnapshot.h | 135 + .../viewplugins/screenshot/ksnapshotwidget.ui | 335 + .../viewplugins/screenshot/ksnapshotwidget.ui.h | 118 + krita/plugins/viewplugins/screenshot/main.cpp | 38 + .../viewplugins/screenshot/regiongrabber.cpp | 170 + .../plugins/viewplugins/screenshot/regiongrabber.h | 71 + .../screenshot/screenshot-kpresenter.rc | 9 + .../viewplugins/screenshot/screenshot-krita.rc | 9 + .../viewplugins/screenshot/screenshot-kword.rc | 9 + .../plugins/viewplugins/screenshot/screenshot.cpp | 78 + krita/plugins/viewplugins/screenshot/screenshot.h | 42 + krita/plugins/viewplugins/scripting/Makefile.am | 28 + .../viewplugins/scripting/kritacore/Makefile.am | 29 + .../scripting/kritacore/kritacoremodule.cpp | 288 + .../scripting/kritacore/kritacoremodule.h | 205 + .../viewplugins/scripting/kritacore/krs_brush.cpp | 41 + .../viewplugins/scripting/kritacore/krs_brush.h | 48 + .../viewplugins/scripting/kritacore/krs_color.cpp | 42 + .../viewplugins/scripting/kritacore/krs_color.h | 49 + .../viewplugins/scripting/kritacore/krs_doc.cpp | 46 + .../viewplugins/scripting/kritacore/krs_doc.h | 53 + .../viewplugins/scripting/kritacore/krs_filter.cpp | 76 + .../viewplugins/scripting/kritacore/krs_filter.h | 76 + .../kritacore/krs_filter_configuration.cpp | 72 + .../scripting/kritacore/krs_filter_configuration.h | 65 + .../scripting/kritacore/krs_histogram.cpp | 104 + .../scripting/kritacore/krs_histogram.h | 115 + .../viewplugins/scripting/kritacore/krs_image.cpp | 148 + .../viewplugins/scripting/kritacore/krs_image.h | 94 + .../viewplugins/scripting/kritacore/krs_iterator.h | 306 + .../scripting/kritacore/krs_paint_layer.cpp | 207 + .../scripting/kritacore/krs_paint_layer.h | 140 + .../scripting/kritacore/krs_painter.cpp | 358 + .../viewplugins/scripting/kritacore/krs_painter.h | 242 + .../scripting/kritacore/krs_pattern.cpp | 39 + .../viewplugins/scripting/kritacore/krs_pattern.h | 48 + .../scripting/kritacore/krs_script_progress.cpp | 67 + .../scripting/kritacore/krs_script_progress.h | 77 + .../scripting/kritacore/krs_wavelet.cpp | 114 + .../viewplugins/scripting/kritacore/krs_wavelet.h | 92 + .../viewplugins/scripting/kritascripting.desktop | 81 + .../scripting/kritascripting/Makefile.am | 19 + .../kritascripting/kis_script_monitor.cpp | 51 + .../scripting/kritascripting/kis_script_monitor.h | 50 + .../kritascripting/kis_script_progress.cpp | 64 + .../scripting/kritascripting/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 + krita/plugins/viewplugins/scripting/scripting.cc | 111 + krita/plugins/viewplugins/scripting/scripting.h | 53 + krita/plugins/viewplugins/scripting/scripting.rc | 10 + krita/plugins/viewplugins/selectopaque/Makefile.am | 24 + .../selectopaque/kritaselectopaque.desktop | 26 + .../viewplugins/selectopaque/selectopaque.cc | 116 + .../viewplugins/selectopaque/selectopaque.h | 44 + .../viewplugins/selectopaque/selectopaque.rc | 10 + .../viewplugins/separate_channels/Makefile.am | 26 + .../viewplugins/separate_channels/dlg_separate.cc | 110 + .../viewplugins/separate_channels/dlg_separate.h | 67 + .../viewplugins/separate_channels/imageseparate.rc | 9 + .../separate_channels/kis_channel_separator.cc | 301 + .../separate_channels/kis_channel_separator.h | 69 + .../kis_separate_channels_plugin.cc | 96 + .../kis_separate_channels_plugin.h | 45 + .../kritaseparatechannels.desktop | 42 + .../separate_channels/wdg_separations.ui | 182 + krita/plugins/viewplugins/shearimage/Makefile.am | 24 + .../viewplugins/shearimage/dlg_shearimage.cc | 96 + .../viewplugins/shearimage/dlg_shearimage.h | 54 + .../viewplugins/shearimage/kritashearimage.desktop | 37 + krita/plugins/viewplugins/shearimage/shearimage.cc | 113 + krita/plugins/viewplugins/shearimage/shearimage.h | 46 + krita/plugins/viewplugins/shearimage/shearimage.rc | 13 + .../viewplugins/shearimage/wdg_shearimage.ui | 102 + krita/plugins/viewplugins/substrate/Makefile.am | 25 + .../plugins/viewplugins/substrate/dlg_substrate.cc | 59 + .../plugins/viewplugins/substrate/dlg_substrate.h | 61 + .../substrate/kis_repeating_substrate.cc | 0 .../substrate/kis_repeating_substrate.h | 69 + .../viewplugins/substrate/kritasubstrate.desktop | 35 + krita/plugins/viewplugins/substrate/substrate.cc | 78 + krita/plugins/viewplugins/substrate/substrate.h | 44 + krita/plugins/viewplugins/substrate/substrate.rc | 8 + .../plugins/viewplugins/substrate/wdgsubstrate.ui | 221 + krita/plugins/viewplugins/variations/Makefile.am | 25 + .../viewplugins/variations/dlg_variations.cc | 58 + .../viewplugins/variations/dlg_variations.h | 61 + .../viewplugins/variations/kritavariations.desktop | 40 + krita/plugins/viewplugins/variations/variations.cc | 88 + krita/plugins/viewplugins/variations/variations.h | 44 + krita/plugins/viewplugins/variations/variations.rc | 8 + .../viewplugins/variations/wdg_variations.ui | 897 + krita/sdk/Makefile.am | 23 + krita/sdk/kis_annotation.h | 89 + krita/sdk/kis_canvas_controller.h | 200 + krita/sdk/kis_canvas_observer.h | 55 + krita/sdk/kis_canvas_subject.h | 192 + krita/sdk/kis_debug_areas.h | 34 + krita/sdk/kis_generic_registry.h | 166 + krita/sdk/kis_global.h | 83 + krita/sdk/kis_id.h | 108 + krita/sdk/kis_integer_maths.h | 111 + krita/sdk/kis_progress_display_interface.h | 76 + krita/sdk/kis_progress_subject.cc | 29 + krita/sdk/kis_progress_subject.h | 44 + krita/sdk/kis_shared_ptr_vector.h | 70 + krita/sdk/kis_undo_adapter.h | 67 + krita/todo-1.6 | 74 + krita/ui/Makefile.am | 75 + krita/ui/imageviewer.cc | 78 + krita/ui/imageviewer.h | 52 + krita/ui/kcurve.cc | 450 + krita/ui/kcurve.h | 79 + krita/ui/kis_aboutdata.h | 68 + krita/ui/kis_autobrush.cc | 177 + krita/ui/kis_autobrush.h | 55 + krita/ui/kis_autogradient.cc | 147 + krita/ui/kis_autogradient.h | 52 + krita/ui/kis_birdeye_box.cc | 311 + krita/ui/kis_birdeye_box.h | 68 + krita/ui/kis_boundary_painter.cc | 81 + krita/ui/kis_boundary_painter.h | 33 + krita/ui/kis_brush_chooser.cc | 102 + krita/ui/kis_brush_chooser.h | 51 + krita/ui/kis_button_event.h | 45 + krita/ui/kis_button_press_event.h | 31 + krita/ui/kis_button_release_event.h | 31 + krita/ui/kis_canvas.cc | 1355 + krita/ui/kis_canvas.h | 381 + krita/ui/kis_canvas_painter.cc | 1440 + krita/ui/kis_canvas_painter.h | 356 + krita/ui/kis_clipboard.cc | 287 + krita/ui/kis_clipboard.h | 79 + krita/ui/kis_cmb_composite.cc | 88 + krita/ui/kis_cmb_composite.h | 70 + krita/ui/kis_cmb_idlist.cc | 97 + krita/ui/kis_cmb_idlist.h | 67 + krita/ui/kis_color_cup.cc | 118 + krita/ui/kis_color_cup.h | 94 + krita/ui/kis_config.cc | 442 + krita/ui/kis_config.h | 143 + krita/ui/kis_controlframe.cc | 343 + krita/ui/kis_controlframe.h | 128 + krita/ui/kis_cursor.cc | 374 + krita/ui/kis_cursor.h | 73 + krita/ui/kis_custom_brush.cc | 158 + krita/ui/kis_custom_brush.h | 62 + krita/ui/kis_custom_image_widget.cc | 110 + krita/ui/kis_custom_image_widget.h | 57 + krita/ui/kis_custom_palette.cc | 151 + krita/ui/kis_custom_palette.h | 61 + krita/ui/kis_custom_pattern.cc | 118 + krita/ui/kis_custom_pattern.h | 60 + krita/ui/kis_dlg_adj_layer_props.cc | 168 + krita/ui/kis_dlg_adj_layer_props.h | 80 + krita/ui/kis_dlg_adjustment_layer.cc | 193 + krita/ui/kis_dlg_adjustment_layer.h | 85 + krita/ui/kis_dlg_apply_profile.cc | 96 + krita/ui/kis_dlg_apply_profile.h | 48 + krita/ui/kis_dlg_image_properties.cc | 173 + krita/ui/kis_dlg_image_properties.h | 61 + krita/ui/kis_dlg_layer_properties.cc | 106 + krita/ui/kis_dlg_layer_properties.h | 53 + krita/ui/kis_dlg_new_layer.cc | 159 + krita/ui/kis_dlg_new_layer.h | 60 + krita/ui/kis_dlg_preferences.cc | 821 + krita/ui/kis_dlg_preferences.h | 270 + krita/ui/kis_doc.cc | 1171 + krita/ui/kis_doc.h | 223 + krita/ui/kis_doc_iface.cc | 67 + krita/ui/kis_doc_iface.h | 50 + krita/ui/kis_double_click_event.h | 31 + krita/ui/kis_double_widget.cc | 147 + krita/ui/kis_double_widget.h | 77 + krita/ui/kis_event.h | 62 + krita/ui/kis_factory.cc | 153 + krita/ui/kis_factory.h | 58 + krita/ui/kis_filter_manager.cc | 408 + krita/ui/kis_filter_manager.h | 86 + krita/ui/kis_filters_listview.cc | 250 + krita/ui/kis_filters_listview.h | 143 + krita/ui/kis_gradient_chooser.cc | 77 + krita/ui/kis_gradient_chooser.h | 61 + krita/ui/kis_gradient_slider_widget.cc | 219 + krita/ui/kis_gradient_slider_widget.h | 79 + krita/ui/kis_grid_drawer.cpp | 223 + krita/ui/kis_grid_drawer.h | 71 + krita/ui/kis_grid_manager.cpp | 156 + krita/ui/kis_grid_manager.h | 64 + krita/ui/kis_histogram_view.cc | 354 + krita/ui/kis_histogram_view.h | 103 + krita/ui/kis_icon_item.cc | 116 + krita/ui/kis_icon_item.h | 48 + krita/ui/kis_iconwidget.cc | 80 + krita/ui/kis_iconwidget.h | 49 + krita/ui/kis_import_catcher.cc | 80 + krita/ui/kis_import_catcher.h | 57 + krita/ui/kis_input_device.cc | 101 + krita/ui/kis_input_device.h | 86 + krita/ui/kis_int_spinbox.cc | 198 + krita/ui/kis_int_spinbox.h | 198 + krita/ui/kis_itemchooser.cc | 81 + krita/ui/kis_itemchooser.h | 64 + krita/ui/kis_label_cursor_pos.cc | 53 + krita/ui/kis_label_cursor_pos.h | 42 + krita/ui/kis_label_progress.cc | 214 + krita/ui/kis_label_progress.h | 65 + krita/ui/kis_label_zoom.cc | 21 + krita/ui/kis_label_zoom.h | 33 + krita/ui/kis_layerbox.cc | 675 + krita/ui/kis_layerbox.h | 123 + krita/ui/kis_layerlist.cc | 220 + krita/ui/kis_layerlist.h | 79 + krita/ui/kis_load_visitor.h | 187 + krita/ui/kis_matrix_widget.ui | 210 + krita/ui/kis_matrix_widget.ui.h | 17 + krita/ui/kis_move_event.h | 31 + krita/ui/kis_multi_bool_filter_widget.cc | 68 + krita/ui/kis_multi_bool_filter_widget.h | 55 + krita/ui/kis_multi_double_filter_widget.cc | 103 + krita/ui/kis_multi_double_filter_widget.h | 77 + krita/ui/kis_multi_integer_filter_widget.cc | 104 + krita/ui/kis_multi_integer_filter_widget.h | 81 + krita/ui/kis_opengl_canvas.cc | 127 + krita/ui/kis_opengl_canvas.h | 72 + krita/ui/kis_opengl_canvas_painter.cc | 849 + krita/ui/kis_opengl_canvas_painter.h | 212 + krita/ui/kis_opengl_image_context.cc | 371 + krita/ui/kis_opengl_image_context.h | 156 + krita/ui/kis_paintop_box.cc | 249 + krita/ui/kis_paintop_box.h | 103 + krita/ui/kis_palette_view.cc | 150 + krita/ui/kis_palette_view.h | 69 + krita/ui/kis_palette_widget.cc | 162 + krita/ui/kis_palette_widget.h | 79 + krita/ui/kis_part_layer.cc | 260 + krita/ui/kis_part_layer.h | 147 + krita/ui/kis_part_layer_handler.cc | 94 + krita/ui/kis_part_layer_handler.h | 57 + krita/ui/kis_pattern_chooser.cc | 57 + krita/ui/kis_pattern_chooser.h | 41 + krita/ui/kis_perspective_grid_manager.cpp | 159 + krita/ui/kis_perspective_grid_manager.h | 54 + krita/ui/kis_populate_visitor.h | 117 + krita/ui/kis_previewdialog.cc | 46 + krita/ui/kis_previewdialog.h | 44 + krita/ui/kis_previewwidget.cc | 409 + krita/ui/kis_previewwidget.h | 140 + krita/ui/kis_previewwidgetbase.ui | 271 + krita/ui/kis_qpaintdevice_canvas.cc | 120 + krita/ui/kis_qpaintdevice_canvas.h | 67 + krita/ui/kis_qpaintdevice_canvas_painter.cc | 647 + krita/ui/kis_qpaintdevice_canvas_painter.h | 189 + krita/ui/kis_resource_mediator.cc | 117 + krita/ui/kis_resource_mediator.h | 72 + krita/ui/kis_resourceserver.cc | 199 + krita/ui/kis_resourceserver.h | 90 + krita/ui/kis_ruler.cc | 367 + krita/ui/kis_ruler.h | 80 + krita/ui/kis_save_visitor.h | 171 + krita/ui/kis_savexml_visitor.h | 144 + krita/ui/kis_selection_manager.cc | 1643 + krita/ui/kis_selection_manager.h | 136 + krita/ui/kis_selection_options.cc | 70 + krita/ui/kis_selection_options.h | 56 + krita/ui/kis_text_brush.cc | 74 + krita/ui/kis_text_brush.h | 70 + krita/ui/kis_tool.cc | 69 + krita/ui/kis_tool.h | 143 + krita/ui/kis_tool_controller.h | 39 + krita/ui/kis_tool_dummy.cc | 111 + krita/ui/kis_tool_dummy.h | 84 + krita/ui/kis_tool_factory.h | 41 + krita/ui/kis_tool_freehand.cc | 354 + krita/ui/kis_tool_freehand.h | 102 + krita/ui/kis_tool_manager.cc | 303 + krita/ui/kis_tool_manager.h | 102 + krita/ui/kis_tool_non_paint.cc | 115 + krita/ui/kis_tool_non_paint.h | 84 + krita/ui/kis_tool_paint.cc | 260 + krita/ui/kis_tool_paint.h | 118 + krita/ui/kis_tool_registry.cc | 111 + krita/ui/kis_tool_registry.h | 59 + krita/ui/kis_tool_shape.cc | 67 + krita/ui/kis_tool_shape.h | 52 + krita/ui/kis_tool_types.h | 34 + krita/ui/kis_view.cc | 4018 ++ krita/ui/kis_view.h | 663 + krita/ui/kis_view_iface.cc | 98 + krita/ui/kis_view_iface.h | 58 + krita/ui/kobirdeyepanel.cpp | 619 + krita/ui/kobirdeyepanel.h | 262 + krita/ui/layerlist.cpp | 1325 + krita/ui/layerlist.h | 268 + krita/ui/squeezedcombobox.cpp | 167 + krita/ui/squeezedcombobox.h | 136 + krita/ui/wdgapplyprofile.ui | 172 + krita/ui/wdgautobrush.ui | 355 + krita/ui/wdgautogradient.ui | 399 + krita/ui/wdgbirdeye.ui | 304 + krita/ui/wdgcolorsettings.ui | 357 + krita/ui/wdgcustombrush.ui | 199 + krita/ui/wdgcustompalette.ui | 88 + krita/ui/wdgcustompattern.ui | 156 + krita/ui/wdgdisplaysettings.ui | 90 + krita/ui/wdggeneralsettings.ui | 183 + krita/ui/wdggridsettings.ui | 468 + krita/ui/wdglayerbox.ui | 299 + krita/ui/wdglayerproperties.ui | 170 + krita/ui/wdgnewimage.ui | 435 + krita/ui/wdgpalettechooser.ui | 105 + krita/ui/wdgperformancesettings.ui | 146 + krita/ui/wdgpressuresettings.ui | 66 + krita/ui/wdgselectionoptions.ui | 64 + krita/ui/wdgshapeoptions.ui | 98 + krita/ui/wdgtabletdevicesettings.ui | 193 + krita/ui/wdgtabletsettings.ui | 104 + krita/ui/wdgtextbrush.ui | 158 + 1621 files changed, 353917 insertions(+) create mode 100644 krita/AUTHORS create mode 100644 krita/ChangeLog create mode 100644 krita/HACKING create mode 100644 krita/IMAGE_LIBRARIES create mode 100644 krita/Makefile.am create mode 100644 krita/README create mode 100644 krita/TODO create mode 100644 krita/UIcomments create mode 100644 krita/colorspaces/Makefile.am create mode 100644 krita/colorspaces/README create mode 100644 krita/colorspaces/cmyk_u16/Makefile.am create mode 100644 krita/colorspaces/cmyk_u16/cmyk_u16_plugin.cc create mode 100644 krita/colorspaces/cmyk_u16/cmyk_u16_plugin.h create mode 100644 krita/colorspaces/cmyk_u16/kis_cmyk_u16_colorspace.cc create mode 100644 krita/colorspaces/cmyk_u16/kis_cmyk_u16_colorspace.h create mode 100644 krita/colorspaces/cmyk_u16/krita_cmyk_u16_plugin.desktop create mode 100644 krita/colorspaces/cmyk_u8/Makefile.am create mode 100644 krita/colorspaces/cmyk_u8/cmyk_plugin.cc create mode 100644 krita/colorspaces/cmyk_u8/cmyk_plugin.h create mode 100644 krita/colorspaces/cmyk_u8/cmykplugin.rc create mode 100644 krita/colorspaces/cmyk_u8/composite.h create mode 100644 krita/colorspaces/cmyk_u8/kis_cmyk_colorspace.cc create mode 100644 krita/colorspaces/cmyk_u8/kis_cmyk_colorspace.h create mode 100644 krita/colorspaces/cmyk_u8/kritacmykplugin.desktop create mode 100644 krita/colorspaces/cmyk_u8/templates/.directory create mode 100644 krita/colorspaces/cmyk_u8/templates/Makefile.am create mode 100644 krita/colorspaces/cmyk_u8/templates/cr48-action-template_cmyk_empty.png create mode 100644 krita/colorspaces/cmyk_u8/templates/crsc-action-template_cmyk_empty.svgz create mode 100644 krita/colorspaces/cmyk_u8/templates/white_2000x800.desktop create mode 100644 krita/colorspaces/cmyk_u8/templates/white_2000x800.kra create mode 100644 krita/colorspaces/gray_u16/Makefile.am create mode 100644 krita/colorspaces/gray_u16/gray_u16_plugin.cc create mode 100644 krita/colorspaces/gray_u16/gray_u16_plugin.h create mode 100644 krita/colorspaces/gray_u16/kis_gray_u16_colorspace.cc create mode 100644 krita/colorspaces/gray_u16/kis_gray_u16_colorspace.h create mode 100644 krita/colorspaces/gray_u16/krita_gray_u16_plugin.desktop create mode 100644 krita/colorspaces/gray_u8/Makefile.am create mode 100644 krita/colorspaces/gray_u8/gray_plugin.cc create mode 100644 krita/colorspaces/gray_u8/gray_plugin.h create mode 100644 krita/colorspaces/gray_u8/grayplugin.rc create mode 100644 krita/colorspaces/gray_u8/kis_gray_colorspace.cc create mode 100644 krita/colorspaces/gray_u8/kis_gray_colorspace.h create mode 100644 krita/colorspaces/gray_u8/kritagrayplugin.desktop create mode 100644 krita/colorspaces/gray_u8/templates/.directory create mode 100644 krita/colorspaces/gray_u8/templates/Makefile.am create mode 100644 krita/colorspaces/gray_u8/templates/cr48-action-template_gray_empty.png create mode 100644 krita/colorspaces/gray_u8/templates/crsc-action-template_gray_empty.svgz create mode 100644 krita/colorspaces/gray_u8/templates/white_640x480.desktop create mode 100644 krita/colorspaces/gray_u8/templates/white_640x480.kra create mode 100644 krita/colorspaces/gray_u8/tests/Makefile.am create mode 100644 krita/colorspaces/gray_u8/tests/kis_strategy_colorspace_grayscale_tester.cpp create mode 100644 krita/colorspaces/gray_u8/tests/kis_strategy_colorspace_grayscale_tester.h create mode 100644 krita/colorspaces/lms_f32/Makefile.am create mode 100644 krita/colorspaces/lms_f32/kis_lms_f32_colorspace.cc create mode 100644 krita/colorspaces/lms_f32/kis_lms_f32_colorspace.h create mode 100644 krita/colorspaces/lms_f32/krita_lms_f32_plugin.desktop create mode 100644 krita/colorspaces/lms_f32/lms_f32_plugin.cc create mode 100644 krita/colorspaces/lms_f32/lms_f32_plugin.h create mode 100644 krita/colorspaces/lms_f32/lms_f32_plugin.rc create mode 100644 krita/colorspaces/rgb_f16half/Makefile.am create mode 100644 krita/colorspaces/rgb_f16half/kis_rgb_f16half_colorspace.cc create mode 100644 krita/colorspaces/rgb_f16half/kis_rgb_f16half_colorspace.h create mode 100644 krita/colorspaces/rgb_f16half/krita_rgb_f16half_plugin.desktop create mode 100644 krita/colorspaces/rgb_f16half/rgb_f16half_plugin.cc create mode 100644 krita/colorspaces/rgb_f16half/rgb_f16half_plugin.h create mode 100644 krita/colorspaces/rgb_f16half/rgb_f16half_plugin.rc create mode 100644 krita/colorspaces/rgb_f16half/tests/Makefile.am create mode 100644 krita/colorspaces/rgb_f16half/tests/kis_rgb_f16half_colorspace_tester.cc create mode 100644 krita/colorspaces/rgb_f16half/tests/kis_rgb_f16half_colorspace_tester.h create mode 100644 krita/colorspaces/rgb_f32/Makefile.am create mode 100644 krita/colorspaces/rgb_f32/kis_rgb_f32_colorspace.cc create mode 100644 krita/colorspaces/rgb_f32/kis_rgb_f32_colorspace.h create mode 100644 krita/colorspaces/rgb_f32/krita_rgb_f32_plugin.desktop create mode 100644 krita/colorspaces/rgb_f32/rgb_f32_plugin.cc create mode 100644 krita/colorspaces/rgb_f32/rgb_f32_plugin.h create mode 100644 krita/colorspaces/rgb_f32/rgb_f32_plugin.rc create mode 100644 krita/colorspaces/rgb_f32/tests/Makefile.am create mode 100644 krita/colorspaces/rgb_f32/tests/kis_strategy_colorspace_rgb_f32_tester.cc create mode 100644 krita/colorspaces/rgb_f32/tests/kis_strategy_colorspace_rgb_f32_tester.h create mode 100644 krita/colorspaces/rgb_u16/Makefile.am create mode 100644 krita/colorspaces/rgb_u16/kis_rgb_u16_colorspace.cc create mode 100644 krita/colorspaces/rgb_u16/kis_rgb_u16_colorspace.h create mode 100644 krita/colorspaces/rgb_u16/krita_rgb_u16_plugin.desktop create mode 100644 krita/colorspaces/rgb_u16/rgb_u16_plugin.cc create mode 100644 krita/colorspaces/rgb_u16/rgb_u16_plugin.h create mode 100644 krita/colorspaces/rgb_u16/tests/Makefile.am create mode 100644 krita/colorspaces/rgb_u16/tests/kis_strategy_colorspace_rgb_u16_tester.cc create mode 100644 krita/colorspaces/rgb_u16/tests/kis_strategy_colorspace_rgb_u16_tester.h create mode 100644 krita/colorspaces/rgb_u8/Makefile.am create mode 100644 krita/colorspaces/rgb_u8/composite.h create mode 100644 krita/colorspaces/rgb_u8/kis_rgb_colorspace.cc create mode 100644 krita/colorspaces/rgb_u8/kis_rgb_colorspace.h create mode 100644 krita/colorspaces/rgb_u8/kritargbplugin.desktop create mode 100644 krita/colorspaces/rgb_u8/rgb_plugin.cc create mode 100644 krita/colorspaces/rgb_u8/rgb_plugin.h create mode 100644 krita/colorspaces/rgb_u8/rgbplugin.rc create mode 100644 krita/colorspaces/rgb_u8/templates/.directory create mode 100644 krita/colorspaces/rgb_u8/templates/Makefile.am create mode 100644 krita/colorspaces/rgb_u8/templates/cr48-action-template_rgb_empty.png create mode 100644 krita/colorspaces/rgb_u8/templates/crsc-action-template_rgb_empty.svgz create mode 100644 krita/colorspaces/rgb_u8/templates/transparent_1024x768.desktop create mode 100644 krita/colorspaces/rgb_u8/templates/transparent_1024x768.kra create mode 100644 krita/colorspaces/rgb_u8/templates/transparent_1280x1024.desktop create mode 100644 krita/colorspaces/rgb_u8/templates/transparent_1280x1024.kra create mode 100644 krita/colorspaces/rgb_u8/templates/transparent_1600x1200.desktop create mode 100644 krita/colorspaces/rgb_u8/templates/transparent_1600x1200.kra create mode 100644 krita/colorspaces/rgb_u8/templates/transparent_640x480.desktop create mode 100644 krita/colorspaces/rgb_u8/templates/transparent_640x480.kra create mode 100644 krita/colorspaces/rgb_u8/templates/white_1024x768.desktop create mode 100644 krita/colorspaces/rgb_u8/templates/white_1024x768.kra create mode 100644 krita/colorspaces/rgb_u8/templates/white_1280x1024.desktop create mode 100644 krita/colorspaces/rgb_u8/templates/white_1280x1024.kra create mode 100644 krita/colorspaces/rgb_u8/templates/white_1600x1200.desktop create mode 100644 krita/colorspaces/rgb_u8/templates/white_1600x1200.kra create mode 100644 krita/colorspaces/rgb_u8/templates/white_640x480.desktop create mode 100644 krita/colorspaces/rgb_u8/templates/white_640x480.kra create mode 100644 krita/colorspaces/rgb_u8/tests/Makefile.am create mode 100644 krita/colorspaces/rgb_u8/tests/kis_strategy_colorspace_rgb_tester.cpp create mode 100644 krita/colorspaces/rgb_u8/tests/kis_strategy_colorspace_rgb_tester.h create mode 100644 krita/colorspaces/wet/Makefile.am create mode 100644 krita/colorspaces/wet/kis_texture_filter.cc create mode 100644 krita/colorspaces/wet/kis_texture_filter.h create mode 100644 krita/colorspaces/wet/kis_texture_painter.cc create mode 100644 krita/colorspaces/wet/kis_texture_painter.h create mode 100644 krita/colorspaces/wet/kis_wet_colorspace.cc create mode 100644 krita/colorspaces/wet/kis_wet_colorspace.h create mode 100644 krita/colorspaces/wet/kis_wet_palette_widget.cc create mode 100644 krita/colorspaces/wet/kis_wet_palette_widget.h create mode 100644 krita/colorspaces/wet/kis_wetness_visualisation_filter.cc create mode 100644 krita/colorspaces/wet/kis_wetness_visualisation_filter.h create mode 100644 krita/colorspaces/wet/kis_wetop.cc create mode 100644 krita/colorspaces/wet/kis_wetop.h create mode 100644 krita/colorspaces/wet/kritawetplugin.desktop create mode 100644 krita/colorspaces/wet/todo create mode 100644 krita/colorspaces/wet/wdgpressure.ui create mode 100644 krita/colorspaces/wet/wet_plugin.cc create mode 100644 krita/colorspaces/wet/wet_plugin.h create mode 100644 krita/colorspaces/wet/wetdreams/Makefile create mode 100644 krita/colorspaces/wet/wetdreams/wetmain.c create mode 100644 krita/colorspaces/wet/wetdreams/wetpaint.c create mode 100644 krita/colorspaces/wet/wetdreams/wetpaint.h create mode 100644 krita/colorspaces/wet/wetdreams/wetphysics.c create mode 100644 krita/colorspaces/wet/wetdreams/wetphysics.h create mode 100644 krita/colorspaces/wet/wetdreams/wetpix.c create mode 100644 krita/colorspaces/wet/wetdreams/wetpix.h create mode 100644 krita/colorspaces/wet/wetdreams/wettexture.c create mode 100644 krita/colorspaces/wet/wetdreams/wettexture.h create mode 100644 krita/colorspaces/wet/wetphysicsfilter.cc create mode 100644 krita/colorspaces/wet/wetphysicsfilter.h create mode 100644 krita/colorspaces/wet/wetplugin.rc create mode 100644 krita/colorspaces/wetsticky/Makefile.am create mode 100644 krita/colorspaces/wetsticky/README create mode 100644 krita/colorspaces/wetsticky/TODO create mode 100644 krita/colorspaces/wetsticky/brushop/Makefile.am create mode 100644 krita/colorspaces/wetsticky/brushop/README create mode 100644 krita/colorspaces/wetsticky/brushop/kis_wsbrushop.cc create mode 100644 krita/colorspaces/wetsticky/brushop/kis_wsbrushop.h create mode 100644 krita/colorspaces/wetsticky/brushop/kritawsbrushpaintop.desktop create mode 100644 krita/colorspaces/wetsticky/brushop/wetpaintbrush.png create mode 100644 krita/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.cc create mode 100644 krita/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.h create mode 100644 krita/colorspaces/wetsticky/kis_wet_sticky_colorspace.cc create mode 100644 krita/colorspaces/wetsticky/kis_wet_sticky_colorspace.h create mode 100644 krita/colorspaces/wetsticky/kis_ws_engine_filter.cc create mode 100644 krita/colorspaces/wetsticky/kis_ws_engine_filter.h create mode 100644 krita/colorspaces/wetsticky/kritawsplugin.desktop create mode 100644 krita/colorspaces/wetsticky/wet_sticky_plugin.cc create mode 100644 krita/colorspaces/wetsticky/wet_sticky_plugin.h create mode 100644 krita/colorspaces/wetsticky/ws/GNU create mode 100644 krita/colorspaces/wetsticky/ws/GNU Public Licence.txt create mode 100644 krita/colorspaces/wetsticky/ws/README create mode 100644 krita/colorspaces/wetsticky/ws/TODO create mode 100644 krita/colorspaces/wetsticky/ws/after.jpg create mode 100644 krita/colorspaces/wetsticky/ws/anim.c create mode 100644 krita/colorspaces/wetsticky/ws/before.jpg create mode 100644 krita/colorspaces/wetsticky/ws/canvas.c create mode 100644 krita/colorspaces/wetsticky/ws/canvas.h create mode 100644 krita/colorspaces/wetsticky/ws/cmap.c create mode 100644 krita/colorspaces/wetsticky/ws/constants.h create mode 100644 krita/colorspaces/wetsticky/ws/engine.c create mode 100644 krita/colorspaces/wetsticky/ws/engine.h create mode 100644 krita/colorspaces/wetsticky/ws/engine3.c create mode 100644 krita/colorspaces/wetsticky/ws/load_ppm.c create mode 100644 krita/colorspaces/wetsticky/ws/main.c create mode 100644 krita/colorspaces/wetsticky/ws/makefile create mode 100644 krita/colorspaces/wetsticky/ws/mona.pgm create mode 100644 krita/colorspaces/wetsticky/ws/ogl_interface.c create mode 100644 krita/colorspaces/wetsticky/ws/test2.jpg create mode 100644 krita/colorspaces/wetsticky/ws/test3.jpg create mode 100644 krita/colorspaces/wetsticky/ws/types.h create mode 100644 krita/colorspaces/wetsticky/ws/win_interface.h create mode 100644 krita/colorspaces/wetsticky/ws/x_interface.c create mode 100644 krita/colorspaces/wetsticky/wstool.ui create mode 100644 krita/colorspaces/ycbcr_u16/Makefile.am create mode 100644 krita/colorspaces/ycbcr_u16/kis_ycbcr_u16_colorspace.cc create mode 100644 krita/colorspaces/ycbcr_u16/kis_ycbcr_u16_colorspace.h create mode 100644 krita/colorspaces/ycbcr_u16/krita_ycbcr_u16_plugin.desktop create mode 100644 krita/colorspaces/ycbcr_u16/ycbcr_u16_plugin.cc create mode 100644 krita/colorspaces/ycbcr_u16/ycbcr_u16_plugin.h create mode 100644 krita/colorspaces/ycbcr_u8/Makefile.am create mode 100644 krita/colorspaces/ycbcr_u8/kis_ycbcr_u8_colorspace.cc create mode 100644 krita/colorspaces/ycbcr_u8/kis_ycbcr_u8_colorspace.h create mode 100644 krita/colorspaces/ycbcr_u8/krita_ycbcr_u8_plugin.desktop create mode 100644 krita/colorspaces/ycbcr_u8/ycbcr_u8_plugin.cc create mode 100644 krita/colorspaces/ycbcr_u8/ycbcr_u8_plugin.h create mode 100644 krita/configure.in.bot create mode 100644 krita/configure.in.in create mode 100644 krita/core/Makefile.am create mode 100755 krita/core/createdcop.py create mode 100644 krita/core/kis_adjustment_layer.cc create mode 100644 krita/core/kis_adjustment_layer.h create mode 100644 krita/core/kis_alpha_mask.cc create mode 100644 krita/core/kis_alpha_mask.h create mode 100644 krita/core/kis_autobrush_resource.cc create mode 100644 krita/core/kis_autobrush_resource.h create mode 100644 krita/core/kis_autogradient_resource.cc create mode 100644 krita/core/kis_autogradient_resource.h create mode 100644 krita/core/kis_background.cc create mode 100644 krita/core/kis_background.h create mode 100644 krita/core/kis_basic_math_toolbox.cpp create mode 100644 krita/core/kis_basic_math_toolbox.h create mode 100644 krita/core/kis_boundary.cc create mode 100644 krita/core/kis_boundary.h create mode 100644 krita/core/kis_brush.cc create mode 100644 krita/core/kis_brush.h create mode 100644 krita/core/kis_change_profile_visitor.h create mode 100644 krita/core/kis_colorspace_convert_visitor.h create mode 100644 krita/core/kis_command.cc create mode 100644 krita/core/kis_command.h create mode 100644 krita/core/kis_convolution_painter.cc create mode 100644 krita/core/kis_convolution_painter.h create mode 100644 krita/core/kis_crop_visitor.h create mode 100644 krita/core/kis_datamanager.h create mode 100644 krita/core/kis_exif_info.cc create mode 100644 krita/core/kis_exif_info.h create mode 100644 krita/core/kis_exif_value.cc create mode 100644 krita/core/kis_exif_value.h create mode 100644 krita/core/kis_fill_painter.cc create mode 100644 krita/core/kis_fill_painter.h create mode 100644 krita/core/kis_filter.cc create mode 100644 krita/core/kis_filter.h create mode 100644 krita/core/kis_filter_config_widget.cc create mode 100644 krita/core/kis_filter_config_widget.h create mode 100644 krita/core/kis_filter_configuration.cc create mode 100644 krita/core/kis_filter_configuration.h create mode 100644 krita/core/kis_filter_registry.cc create mode 100644 krita/core/kis_filter_registry.h create mode 100644 krita/core/kis_filter_strategy.cc create mode 100644 krita/core/kis_filter_strategy.h create mode 100644 krita/core/kis_gradient.cc create mode 100644 krita/core/kis_gradient.h create mode 100644 krita/core/kis_gradient_painter.cc create mode 100644 krita/core/kis_gradient_painter.h create mode 100644 krita/core/kis_group_layer.cc create mode 100644 krita/core/kis_group_layer.h create mode 100644 krita/core/kis_histogram.cc create mode 100644 krita/core/kis_histogram.h create mode 100644 krita/core/kis_image.cc create mode 100644 krita/core/kis_image.h create mode 100644 krita/core/kis_image_iface.cc create mode 100644 krita/core/kis_image_iface.h create mode 100644 krita/core/kis_imagepipe_brush.cc create mode 100644 krita/core/kis_imagepipe_brush.h create mode 100644 krita/core/kis_iterator.cc create mode 100644 krita/core/kis_iterator.h create mode 100644 krita/core/kis_iteratorpixeltrait.h create mode 100644 krita/core/kis_iterators_pixel.cc create mode 100644 krita/core/kis_iterators_pixel.h create mode 100644 krita/core/kis_layer.cc create mode 100644 krita/core/kis_layer.h create mode 100644 krita/core/kis_layer_visitor.h create mode 100644 krita/core/kis_math_toolbox.cpp create mode 100644 krita/core/kis_math_toolbox.h create mode 100644 krita/core/kis_merge_visitor.h create mode 100644 krita/core/kis_meta_registry.cc create mode 100644 krita/core/kis_meta_registry.h create mode 100644 krita/core/kis_nameserver.cc create mode 100644 krita/core/kis_nameserver.h create mode 100644 krita/core/kis_paint_device.cc create mode 100644 krita/core/kis_paint_device.h create mode 100644 krita/core/kis_paint_device_action.h create mode 100644 krita/core/kis_paint_device_iface.cc create mode 100644 krita/core/kis_paint_device_iface.h create mode 100644 krita/core/kis_paint_layer.cc create mode 100644 krita/core/kis_paint_layer.h create mode 100644 krita/core/kis_painter.cc create mode 100644 krita/core/kis_painter.h create mode 100644 krita/core/kis_paintop.cc create mode 100644 krita/core/kis_paintop.h create mode 100644 krita/core/kis_paintop_registry.cc create mode 100644 krita/core/kis_paintop_registry.h create mode 100644 krita/core/kis_palette.cc create mode 100644 krita/core/kis_palette.h create mode 100644 krita/core/kis_part_layer_iface.h create mode 100644 krita/core/kis_pattern.cc create mode 100644 krita/core/kis_pattern.h create mode 100644 krita/core/kis_perspective_grid.cpp create mode 100644 krita/core/kis_perspective_grid.h create mode 100644 krita/core/kis_perspective_math.cpp create mode 100644 krita/core/kis_perspective_math.h create mode 100644 krita/core/kis_perspectivetransform_worker.cpp create mode 100644 krita/core/kis_perspectivetransform_worker.h create mode 100644 krita/core/kis_point.h create mode 100644 krita/core/kis_random_accessor.cpp create mode 100644 krita/core/kis_random_accessor.h create mode 100644 krita/core/kis_random_sub_accessor.cpp create mode 100644 krita/core/kis_random_sub_accessor.h create mode 100644 krita/core/kis_rect.cc create mode 100644 krita/core/kis_rect.h create mode 100644 krita/core/kis_resource.cc create mode 100644 krita/core/kis_resource.h create mode 100644 krita/core/kis_rotate_visitor.cc create mode 100644 krita/core/kis_rotate_visitor.h create mode 100644 krita/core/kis_scale_visitor.cc create mode 100644 krita/core/kis_scale_visitor.h create mode 100644 krita/core/kis_selected_transaction.cc create mode 100644 krita/core/kis_selected_transaction.h create mode 100644 krita/core/kis_selection.cc create mode 100644 krita/core/kis_selection.h create mode 100644 krita/core/kis_shear_visitor.h create mode 100644 krita/core/kis_strategy_move.cc create mode 100644 krita/core/kis_strategy_move.h create mode 100644 krita/core/kis_substrate.h create mode 100644 krita/core/kis_thread.h create mode 100644 krita/core/kis_thread_pool.cc create mode 100644 krita/core/kis_thread_pool.h create mode 100644 krita/core/kis_transaction.cc create mode 100644 krita/core/kis_transaction.h create mode 100644 krita/core/kis_transform_visitor.h create mode 100644 krita/core/kis_transform_worker.cc create mode 100644 krita/core/kis_transform_worker.h create mode 100644 krita/core/kis_types.h create mode 100644 krita/core/kis_vec.cc create mode 100644 krita/core/kis_vec.h create mode 100644 krita/core/tests/Makefile.am create mode 100644 krita/core/tests/kis_filter_configuration_tester.cc create mode 100644 krita/core/tests/kis_filter_configuration_tester.h create mode 100644 krita/core/tests/kis_image_tester.cpp create mode 100644 krita/core/tests/kis_image_tester.h create mode 100644 krita/core/tests/kis_integer_maths_tester.cpp create mode 100644 krita/core/tests/kis_integer_maths_tester.h create mode 100644 krita/core/tiles/Makefile.am create mode 100644 krita/core/tiles/kis_memento.cc create mode 100644 krita/core/tiles/kis_memento.h create mode 100644 krita/core/tiles/kis_tile.cc create mode 100644 krita/core/tiles/kis_tile.h create mode 100644 krita/core/tiles/kis_tile_global.h create mode 100644 krita/core/tiles/kis_tiled_random_accessor.cc create mode 100644 krita/core/tiles/kis_tiled_random_accessor.h create mode 100644 krita/core/tiles/kis_tileddatamanager.cc create mode 100644 krita/core/tiles/kis_tileddatamanager.h create mode 100644 krita/core/tiles/kis_tiledhlineiterator.cc create mode 100644 krita/core/tiles/kis_tilediterator.cc create mode 100644 krita/core/tiles/kis_tilediterator.h create mode 100644 krita/core/tiles/kis_tiledrectiterator.cc create mode 100644 krita/core/tiles/kis_tiledvlineiterator.cc create mode 100644 krita/core/tiles/kis_tilemanager.cc create mode 100644 krita/core/tiles/kis_tilemanager.h create mode 100644 krita/core/tiles/tests/Makefile.am create mode 100644 krita/core/tiles/tests/kis_tiled_data_tester.cpp create mode 100644 krita/core/tiles/tests/kis_tiled_data_tester.h create mode 100644 krita/data/Makefile.am create mode 100644 krita/data/README create mode 100644 krita/data/brushes/10x10square.gbr create mode 100644 krita/data/brushes/10x10squareBlur.gbr create mode 100644 krita/data/brushes/11circle.gbr create mode 100644 krita/data/brushes/11fcircle.gbr create mode 100644 krita/data/brushes/13circle.gbr create mode 100644 krita/data/brushes/13fcircle.gbr create mode 100644 krita/data/brushes/15circle.gbr create mode 100644 krita/data/brushes/15fcircle.gbr create mode 100644 krita/data/brushes/17circle.gbr create mode 100644 krita/data/brushes/17fcircle.gbr create mode 100644 krita/data/brushes/19circle.gbr create mode 100644 krita/data/brushes/19fcircle.gbr create mode 100644 krita/data/brushes/1circle.gbr create mode 100644 krita/data/brushes/20x20square.gbr create mode 100644 krita/data/brushes/20x20squareBlur.gbr create mode 100644 krita/data/brushes/3circle.gbr create mode 100644 krita/data/brushes/3fcircle.gbr create mode 100644 krita/data/brushes/5circle.gbr create mode 100644 krita/data/brushes/5fcircle.gbr create mode 100644 krita/data/brushes/5x5square.gbr create mode 100644 krita/data/brushes/5x5squareBlur.gbr create mode 100644 krita/data/brushes/7circle.gbr create mode 100644 krita/data/brushes/7fcircle.gbr create mode 100644 krita/data/brushes/9circle.gbr create mode 100644 krita/data/brushes/9fcircle.gbr create mode 100644 krita/data/brushes/BRUSHES.README create mode 100644 krita/data/brushes/COPYING create mode 100644 krita/data/brushes/DStar11.gbr create mode 100644 krita/data/brushes/DStar17.gbr create mode 100644 krita/data/brushes/DStar25.gbr create mode 100644 krita/data/brushes/Makefile.am create mode 100644 krita/data/brushes/SketchBrush-16.gih create mode 100644 krita/data/brushes/SketchBrush-32.gih create mode 100644 krita/data/brushes/SketchBrush-64.gih create mode 100644 krita/data/brushes/callig1.gbr create mode 100644 krita/data/brushes/callig2.gbr create mode 100644 krita/data/brushes/callig3.gbr create mode 100644 krita/data/brushes/callig4.gbr create mode 100644 krita/data/brushes/confetti.gbr create mode 100644 krita/data/brushes/confetti.gih create mode 100644 krita/data/brushes/cursor.gbr create mode 100644 krita/data/brushes/cursor_big_lb.gbr create mode 100644 krita/data/brushes/cursor_big_lw.gbr create mode 100644 krita/data/brushes/cursor_big_rb.gbr create mode 100644 krita/data/brushes/cursor_big_rw.gbr create mode 100644 krita/data/brushes/cursor_lw.gbr create mode 100644 krita/data/brushes/cursor_resize_diag_1.gbr create mode 100644 krita/data/brushes/cursor_resize_diag_2.gbr create mode 100644 krita/data/brushes/cursor_resize_hor.gbr create mode 100644 krita/data/brushes/cursor_resize_vert.gbr create mode 100644 krita/data/brushes/cursor_rw.gbr create mode 100644 krita/data/brushes/cursor_small_lb.gbr create mode 100644 krita/data/brushes/cursor_small_lw.gbr create mode 100644 krita/data/brushes/cursor_small_rb.gbr create mode 100644 krita/data/brushes/cursor_small_rw.gbr create mode 100644 krita/data/brushes/cursor_tiny_lw.gbr create mode 100644 krita/data/brushes/cursor_tiny_rw.gbr create mode 100644 krita/data/brushes/cursor_up.gbr create mode 100644 krita/data/brushes/dunes.gbr create mode 100644 krita/data/brushes/feltpen.gih create mode 100644 krita/data/brushes/galaxy.gbr create mode 100644 krita/data/brushes/galaxy_big.gbr create mode 100644 krita/data/brushes/galaxy_small.gbr create mode 100644 krita/data/brushes/hsparks.gih create mode 100644 krita/data/brushes/pepper.gbr create mode 100644 krita/data/brushes/pixel.gbr create mode 100644 krita/data/brushes/vine.gih create mode 100644 krita/data/gradients/Abstract_1.ggr create mode 100644 krita/data/gradients/Abstract_2.ggr create mode 100644 krita/data/gradients/Abstract_3.ggr create mode 100644 krita/data/gradients/Aneurism.ggr create mode 100644 krita/data/gradients/Blinds.ggr create mode 100644 krita/data/gradients/Blue_Green.ggr create mode 100644 krita/data/gradients/Browns.ggr create mode 100644 krita/data/gradients/Brushed_Aluminium.ggr create mode 100644 krita/data/gradients/Burning_Paper.ggr create mode 100644 krita/data/gradients/Burning_Transparency.ggr create mode 100644 krita/data/gradients/CD.ggr create mode 100644 krita/data/gradients/CD_Half.ggr create mode 100644 krita/data/gradients/Caribbean_Blues.ggr create mode 100644 krita/data/gradients/Coffee.ggr create mode 100644 krita/data/gradients/Cold_Steel.ggr create mode 100644 krita/data/gradients/Cold_Steel_2.ggr create mode 100644 krita/data/gradients/Crown_molding.ggr create mode 100644 krita/data/gradients/Dark_1.ggr create mode 100644 krita/data/gradients/Deep_Sea.ggr create mode 100644 krita/data/gradients/Default.ggr create mode 100644 krita/data/gradients/Flare_Glow_Angular_1.ggr create mode 100644 krita/data/gradients/Flare_Glow_Radial_1.ggr create mode 100644 krita/data/gradients/Flare_Glow_Radial_2.ggr create mode 100644 krita/data/gradients/Flare_Glow_Radial_3.ggr create mode 100644 krita/data/gradients/Flare_Glow_Radial_4.ggr create mode 100644 krita/data/gradients/Flare_Radial_101.ggr create mode 100644 krita/data/gradients/Flare_Radial_102.ggr create mode 100644 krita/data/gradients/Flare_Radial_103.ggr create mode 100644 krita/data/gradients/Flare_Rays_Radial_1.ggr create mode 100644 krita/data/gradients/Flare_Rays_Radial_2.ggr create mode 100644 krita/data/gradients/Flare_Rays_Size_1.ggr create mode 100644 krita/data/gradients/Flare_Sizefac_101.ggr create mode 100644 krita/data/gradients/Four_bars.ggr create mode 100644 krita/data/gradients/French_flag.ggr create mode 100644 krita/data/gradients/French_flag_smooth.ggr create mode 100644 krita/data/gradients/Full_saturation_spectrum_CCW.ggr create mode 100644 krita/data/gradients/Full_saturation_spectrum_CW.ggr create mode 100644 krita/data/gradients/German_flag.ggr create mode 100644 krita/data/gradients/German_flag_smooth.ggr create mode 100644 krita/data/gradients/Golden.ggr create mode 100644 krita/data/gradients/Greens.ggr create mode 100644 krita/data/gradients/Horizon_1.ggr create mode 100644 krita/data/gradients/Horizon_2.ggr create mode 100644 krita/data/gradients/Incandescent.ggr create mode 100644 krita/data/gradients/Land_1.ggr create mode 100644 krita/data/gradients/Land_and_Sea.ggr create mode 100644 krita/data/gradients/Makefile.am create mode 100644 krita/data/gradients/Metallic_Something.ggr create mode 100644 krita/data/gradients/Mexican_flag.ggr create mode 100644 krita/data/gradients/Mexican_flag_smooth.ggr create mode 100644 krita/data/gradients/Nauseating_Headache.ggr create mode 100644 krita/data/gradients/Neon_Cyan.ggr create mode 100644 krita/data/gradients/Neon_Green.ggr create mode 100644 krita/data/gradients/Neon_Yellow.ggr create mode 100644 krita/data/gradients/Pastel_Rainbow.ggr create mode 100644 krita/data/gradients/Pastels.ggr create mode 100644 krita/data/gradients/Purples.ggr create mode 100644 krita/data/gradients/Radial_Eyeball_Blue.ggr create mode 100644 krita/data/gradients/Radial_Eyeball_Brown.ggr create mode 100644 krita/data/gradients/Radial_Eyeball_Green.ggr create mode 100644 krita/data/gradients/Radial_Glow_1.ggr create mode 100644 krita/data/gradients/Radial_Rainbow_Hoop.ggr create mode 100644 krita/data/gradients/Romanian_flag.ggr create mode 100644 krita/data/gradients/Romanian_flag_smooth.ggr create mode 100644 krita/data/gradients/Rounded_edge.ggr create mode 100644 krita/data/gradients/Shadows_1.ggr create mode 100644 krita/data/gradients/Shadows_2.ggr create mode 100644 krita/data/gradients/Shadows_3.ggr create mode 100644 krita/data/gradients/Skyline.ggr create mode 100644 krita/data/gradients/Skyline_polluted.ggr create mode 100644 krita/data/gradients/Square_Wood_Frame.ggr create mode 100644 krita/data/gradients/Sunrise.ggr create mode 100644 krita/data/gradients/Three_bars_sin.ggr create mode 100644 krita/data/gradients/Tropical_Colors.ggr create mode 100644 krita/data/gradients/Tube_Red.ggr create mode 100644 krita/data/gradients/Wood_1.ggr create mode 100644 krita/data/gradients/Wood_2.ggr create mode 100644 krita/data/gradients/Yellow_Contrast.ggr create mode 100644 krita/data/gradients/Yellow_Orange.ggr create mode 100644 krita/data/images/Azay-Le-Rideau.jpg create mode 100644 krita/data/images/Makefile.am create mode 100644 krita/data/images/WeyDesc.png create mode 100644 krita/data/images/evenings.jpg create mode 100644 krita/data/images/hakonepa.jpg create mode 100644 krita/data/images/hiro_awate.jpg create mode 100644 krita/data/images/paintbrush.png create mode 100644 krita/data/images/previewfilter.png create mode 100644 krita/data/krita_filter.desktop create mode 100644 krita/data/krita_paintop.desktop create mode 100644 krita/data/krita_plugin.desktop create mode 100644 krita/data/krita_tool.desktop create mode 100644 krita/data/palettes/40_Colors.gpl create mode 100644 krita/data/palettes/Anchor.gpl create mode 100644 krita/data/palettes/Bears.gpl create mode 100644 krita/data/palettes/Bgold.gpl create mode 100644 krita/data/palettes/Blues.gpl create mode 100644 krita/data/palettes/Borders.gpl create mode 100644 krita/data/palettes/Browns_And_Yellows.gpl create mode 100644 krita/data/palettes/Caramel.gpl create mode 100644 krita/data/palettes/Cascade.gpl create mode 100644 krita/data/palettes/China.gpl create mode 100644 krita/data/palettes/Coldfire.gpl create mode 100644 krita/data/palettes/Cool_Colors.gpl create mode 100644 krita/data/palettes/Cranes.gpl create mode 100644 krita/data/palettes/DMC.gpl create mode 100644 krita/data/palettes/Dark_pastels.gpl create mode 100644 krita/data/palettes/Default.gpl create mode 100644 krita/data/palettes/Ega.gpl create mode 100644 krita/data/palettes/Firecode.gpl create mode 100644 krita/data/palettes/Gold.gpl create mode 100644 krita/data/palettes/GrayViolet.gpl create mode 100644 krita/data/palettes/Grayblue.gpl create mode 100644 krita/data/palettes/Grays.gpl create mode 100644 krita/data/palettes/Greens.gpl create mode 100644 krita/data/palettes/Hilite.gpl create mode 100644 krita/data/palettes/Khaki.gpl create mode 100644 krita/data/palettes/Lights.gpl create mode 100644 krita/data/palettes/Madeira.gpl create mode 100644 krita/data/palettes/Makefile.am create mode 100644 krita/data/palettes/Muted.gpl create mode 100644 krita/data/palettes/Named_Colors.gpl create mode 100644 krita/data/palettes/News3.gpl create mode 100644 krita/data/palettes/Op2.gpl create mode 100644 krita/data/palettes/Paintjet.gpl create mode 100644 krita/data/palettes/Pantone_Coated_Approx.gpl create mode 100644 krita/data/palettes/Pastels.gpl create mode 100644 krita/data/palettes/Plasma.gpl create mode 100644 krita/data/palettes/Reds.gpl create mode 100644 krita/data/palettes/Reds_And_Purples.gpl create mode 100644 krita/data/palettes/Royal.gpl create mode 100644 krita/data/palettes/Topographic.gpl create mode 100644 krita/data/palettes/Visibone.gpl create mode 100644 krita/data/palettes/Visibone_2.gpl create mode 100644 krita/data/palettes/Volcano.gpl create mode 100644 krita/data/palettes/Warm_Colors.gpl create mode 100644 krita/data/palettes/Web.gpl create mode 100644 krita/data/palettes/new_kde.gpl create mode 100644 krita/data/patterns/3dgreen.pat create mode 100644 krita/data/patterns/Craters.pat create mode 100644 krita/data/patterns/Makefile.am create mode 100644 krita/data/patterns/Moonfoot.pat create mode 100644 krita/data/patterns/Stripes1px.pat create mode 100644 krita/data/patterns/Stripes2px.pat create mode 100644 krita/data/patterns/amethyst.pat create mode 100644 krita/data/patterns/bark.pat create mode 100644 krita/data/patterns/blue.pat create mode 100644 krita/data/patterns/bluegrid.pat create mode 100644 krita/data/patterns/bluesquares.pat create mode 100644 krita/data/patterns/blueweb.pat create mode 100644 krita/data/patterns/brick.pat create mode 100644 krita/data/patterns/burlap.pat create mode 100644 krita/data/patterns/burlwood.pat create mode 100644 krita/data/patterns/choc_swirl.pat create mode 100644 krita/data/patterns/corkboard.pat create mode 100644 krita/data/patterns/cracked.pat create mode 100644 krita/data/patterns/crinklepaper.pat create mode 100644 krita/data/patterns/electric.pat create mode 100644 krita/data/patterns/fibers.pat create mode 100644 krita/data/patterns/granite1.pat create mode 100644 krita/data/patterns/ground1.pat create mode 100644 krita/data/patterns/ice.pat create mode 100644 krita/data/patterns/java.pat create mode 100644 krita/data/patterns/leather.pat create mode 100644 krita/data/patterns/leaves.pat create mode 100644 krita/data/patterns/leopard.pat create mode 100644 krita/data/patterns/lightning.pat create mode 100644 krita/data/patterns/marble1.pat create mode 100644 krita/data/patterns/marble2.pat create mode 100644 krita/data/patterns/marble3.pat create mode 100644 krita/data/patterns/nops.pat create mode 100644 krita/data/patterns/paper.pat create mode 100644 krita/data/patterns/parque1.pat create mode 100644 krita/data/patterns/parque2.pat create mode 100644 krita/data/patterns/parque3.pat create mode 100644 krita/data/patterns/pastel.pat create mode 100644 krita/data/patterns/pine.pat create mode 100644 krita/data/patterns/pink_marble.pat create mode 100644 krita/data/patterns/pool.pat create mode 100644 krita/data/patterns/qube1.pat create mode 100644 krita/data/patterns/rain.pat create mode 100644 krita/data/patterns/recessed.pat create mode 100644 krita/data/patterns/redcube.pat create mode 100644 krita/data/patterns/rock.pat create mode 100644 krita/data/patterns/sky.pat create mode 100644 krita/data/patterns/slate.pat create mode 100644 krita/data/patterns/sm_squares.pat create mode 100644 krita/data/patterns/starfield.pat create mode 100644 krita/data/patterns/stone33.pat create mode 100644 krita/data/patterns/terra.pat create mode 100644 krita/data/patterns/walnut.pat create mode 100644 krita/data/patterns/warning.pat create mode 100644 krita/data/patterns/wood1.pat create mode 100644 krita/data/patterns/wood2.pat create mode 100644 krita/data/patterns/wood3.pat create mode 100644 krita/data/patterns/wood4.pat create mode 100644 krita/data/patterns/wood5.pat create mode 100644 krita/data/profiles/Adobe.icm create mode 100644 krita/data/profiles/Apple.icm create mode 100644 krita/data/profiles/CIE.icm create mode 100644 krita/data/profiles/CMY.icm create mode 100644 krita/data/profiles/ColorMatch.icm create mode 100644 krita/data/profiles/Makefile.am create mode 100644 krita/data/profiles/NTSC.icm create mode 100644 krita/data/profiles/PAL.icm create mode 100644 krita/data/profiles/README create mode 100644 krita/data/profiles/SMPTE-C.icm create mode 100644 krita/data/profiles/WideGamut.icm create mode 100644 krita/data/profiles/cmyk.icm create mode 100644 krita/data/profiles/fogra27l.icm create mode 100644 krita/data/profiles/lcmslabi.icm create mode 100644 krita/data/profiles/lcmsxyzi.icm create mode 100644 krita/data/profiles/monoscnr.icm create mode 100644 krita/data/profiles/sRGB.icm create mode 100644 krita/data/profiles/srgb_color_space_profile.icm create mode 100644 krita/data/profiles/srgbspac.icm create mode 100644 krita/data/profiles/tifflab8spac.icm create mode 100644 krita/data/profiles/ycc601.icm create mode 100644 krita/data/profiles/ycc709.icm create mode 100644 krita/data/templates/.directory create mode 100644 krita/design.h create mode 100644 krita/doc/DESIGN.obsolete create mode 100644 krita/doc/Developing Krita Plugins.odt create mode 100644 krita/doc/autoextending paintdevices create mode 100644 krita/doc/background_paper.txt create mode 100644 krita/doc/brush.txt create mode 100644 krita/doc/channels_masks_selections create mode 100644 krita/doc/colordiff create mode 100644 krita/doc/colorspaces.xmi create mode 100644 krita/doc/colorstrategyAPI create mode 100644 krita/doc/controller.xmi create mode 100644 krita/doc/coordinates.txt create mode 100644 krita/doc/dirty.txt create mode 100644 krita/doc/doc-outline create mode 100644 krita/doc/histograms.xmi create mode 100644 krita/doc/hooks create mode 100644 krita/doc/howtofilters.txt create mode 100644 krita/doc/impexp.txt create mode 100644 krita/doc/krita-features create mode 100644 krita/doc/krita.kpr create mode 100644 krita/doc/krita.pdf create mode 100644 krita/doc/krita.xmi create mode 100644 krita/doc/large_files create mode 100644 krita/doc/layersupdatesignals.flw create mode 100644 krita/doc/manual/krita.kwd create mode 100644 krita/doc/oasis create mode 100644 krita/doc/paint_device.txt create mode 100644 krita/doc/palettedesign.txt create mode 100644 krita/doc/plugins.txt create mode 100644 krita/doc/profiles.txt create mode 100644 krita/doc/resolution.txt create mode 100644 krita/doc/scripts/dcop.py create mode 100644 krita/doc/sdk create mode 100644 krita/doc/selections create mode 100644 krita/doc/the preview widget create mode 100644 krita/doc/transform_undo.txt create mode 100644 krita/dtd/Makefile.am create mode 100644 krita/dtd/krita.dtd create mode 100755 krita/extracti18n.pl create mode 100644 krita/krita.desktop create mode 100644 krita/krita.rc create mode 100644 krita/krita_part_init.cc create mode 100644 krita/krita_readonly.rc create mode 100644 krita/kritacolor/Makefile.am create mode 100644 krita/kritacolor/README create mode 100644 krita/kritacolor/TODO create mode 100644 krita/kritacolor/colorspaces/Makefile.am create mode 100644 krita/kritacolor/colorspaces/kis_alpha_colorspace.cc create mode 100644 krita/kritacolor/colorspaces/kis_alpha_colorspace.h create mode 100644 krita/kritacolor/colorspaces/kis_lab_colorspace.cc create mode 100644 krita/kritacolor/colorspaces/kis_lab_colorspace.h create mode 100644 krita/kritacolor/colorspaces/kis_xyz_colorspace.cc create mode 100644 krita/kritacolor/colorspaces/kis_xyz_colorspace.h create mode 100644 krita/kritacolor/kis_abstract_colorspace.cc create mode 100644 krita/kritacolor/kis_abstract_colorspace.h create mode 100644 krita/kritacolor/kis_basic_histogram_producers.cc create mode 100644 krita/kritacolor/kis_basic_histogram_producers.h create mode 100644 krita/kritacolor/kis_channelinfo.h create mode 100644 krita/kritacolor/kis_color.cc create mode 100644 krita/kritacolor/kis_color.h create mode 100644 krita/kritacolor/kis_color_conversions.cc create mode 100644 krita/kritacolor/kis_color_conversions.h create mode 100644 krita/kritacolor/kis_colorspace.cc create mode 100644 krita/kritacolor/kis_colorspace.h create mode 100644 krita/kritacolor/kis_colorspace_factory_registry.cc create mode 100644 krita/kritacolor/kis_colorspace_factory_registry.h create mode 100644 krita/kritacolor/kis_colorspace_iface.cc create mode 100644 krita/kritacolor/kis_colorspace_iface.h create mode 100644 krita/kritacolor/kis_composite_op.cc create mode 100644 krita/kritacolor/kis_composite_op.h create mode 100644 krita/kritacolor/kis_f16half_base_colorspace.cc create mode 100644 krita/kritacolor/kis_f16half_base_colorspace.h create mode 100644 krita/kritacolor/kis_f32_base_colorspace.cc create mode 100644 krita/kritacolor/kis_f32_base_colorspace.h create mode 100644 krita/kritacolor/kis_histogram_producer.cc create mode 100644 krita/kritacolor/kis_histogram_producer.h create mode 100644 krita/kritacolor/kis_profile.cc create mode 100644 krita/kritacolor/kis_profile.h create mode 100644 krita/kritacolor/kis_u16_base_colorspace.cc create mode 100644 krita/kritacolor/kis_u16_base_colorspace.h create mode 100644 krita/kritacolor/kis_u8_base_colorspace.cc create mode 100644 krita/kritacolor/kis_u8_base_colorspace.h create mode 100644 krita/kritacolor/krita_colorspace.desktop create mode 100644 krita/kritacolor/tests/Makefile.am create mode 100644 krita/kritacolor/tests/kis_color_conversions_tester.cpp create mode 100644 krita/kritacolor/tests/kis_color_conversions_tester.h create mode 100644 krita/kritapart.desktop create mode 100644 krita/main.cc create mode 100644 krita/pics/Makefile.am create mode 100644 krita/pics/deletelayer.png create mode 100644 krita/pics/height.png create mode 100644 krita/pics/hi128-app-krita.png create mode 100644 krita/pics/hi16-app-krita.png create mode 100644 krita/pics/hi22-app-krita.png create mode 100644 krita/pics/hi32-app-krita.png create mode 100644 krita/pics/hi48-app-krita.png create mode 100644 krita/pics/hi64-app-krita.png create mode 100644 krita/pics/krita.svg create mode 100644 krita/pics/linked.png create mode 100644 krita/pics/locked.png create mode 100644 krita/pics/lowerlayer.png create mode 100644 krita/pics/newlayer.png create mode 100644 krita/pics/novisible.png create mode 100644 krita/pics/raiselayer.png create mode 100644 krita/pics/shade.png create mode 100644 krita/pics/tablet.png create mode 100644 krita/pics/tool_screenshot.png create mode 100644 krita/pics/unlinked.png create mode 100644 krita/pics/unlocked.png create mode 100644 krita/pics/visible.png create mode 100644 krita/pics/width.png create mode 100644 krita/plugins/Makefile.am create mode 100644 krita/plugins/README create mode 100644 krita/plugins/configure.in.in create mode 100644 krita/plugins/filters/Makefile.am create mode 100644 krita/plugins/filters/blur/Makefile.am create mode 100644 krita/plugins/filters/blur/blur.cc create mode 100644 krita/plugins/filters/blur/blur.h create mode 100644 krita/plugins/filters/blur/kis_blur_filter.cc create mode 100644 krita/plugins/filters/blur/kis_blur_filter.h create mode 100644 krita/plugins/filters/blur/kis_wdg_blur.cc create mode 100644 krita/plugins/filters/blur/kis_wdg_blur.h create mode 100644 krita/plugins/filters/blur/kritablurfilter.desktop create mode 100644 krita/plugins/filters/blur/wdgblur.ui create mode 100644 krita/plugins/filters/bumpmap/Makefile.am create mode 100644 krita/plugins/filters/bumpmap/bumpmap.cc create mode 100644 krita/plugins/filters/bumpmap/bumpmap.h create mode 100644 krita/plugins/filters/bumpmap/kritabumpmapfilter.desktop create mode 100644 krita/plugins/filters/bumpmap/wdgbumpmap.ui create mode 100644 krita/plugins/filters/cimg/.kdev_ignore create mode 100644 krita/plugins/filters/cimg/CImg.h create mode 100644 krita/plugins/filters/cimg/Makefile.am create mode 100644 krita/plugins/filters/cimg/kis_cimg_filter.cc create mode 100644 krita/plugins/filters/cimg/kis_cimg_filter.h create mode 100644 krita/plugins/filters/cimg/kis_cimg_plugin.cc create mode 100644 krita/plugins/filters/cimg/kis_cimg_plugin.h create mode 100644 krita/plugins/filters/cimg/kis_cimgconfig_widget.cc create mode 100644 krita/plugins/filters/cimg/kis_cimgconfig_widget.h create mode 100644 krita/plugins/filters/cimg/kritacimg.desktop create mode 100644 krita/plugins/filters/cimg/wdg_cimg.ui create mode 100644 krita/plugins/filters/colorify/Colorify.cpp create mode 100644 krita/plugins/filters/colorify/Colorify.h create mode 100644 krita/plugins/filters/colorify/KisWdgColorify.cpp create mode 100644 krita/plugins/filters/colorify/KisWdgColorify.h create mode 100644 krita/plugins/filters/colorify/Makefile.am create mode 100644 krita/plugins/filters/colorify/WdgColorifyBase.ui create mode 100644 krita/plugins/filters/colorify/kritacolorifyfilter.desktop create mode 100644 krita/plugins/filters/colors/Makefile.am create mode 100644 krita/plugins/filters/colors/colors.cc create mode 100644 krita/plugins/filters/colors/colors.h create mode 100644 krita/plugins/filters/colors/kis_color_to_alpha.cc create mode 100644 krita/plugins/filters/colors/kis_color_to_alpha.h create mode 100644 krita/plugins/filters/colors/kis_minmax_filters.cc create mode 100644 krita/plugins/filters/colors/kis_minmax_filters.h create mode 100644 krita/plugins/filters/colors/kis_wdg_color_to_alpha.cc create mode 100644 krita/plugins/filters/colors/kis_wdg_color_to_alpha.h create mode 100644 krita/plugins/filters/colors/kritaextensioncolorsfilters.desktop create mode 100644 krita/plugins/filters/colors/wdgcolortoalphabase.ui create mode 100644 krita/plugins/filters/colorsfilters/Makefile.am create mode 100644 krita/plugins/filters/colorsfilters/colorsfilters.cc create mode 100644 krita/plugins/filters/colorsfilters/colorsfilters.h create mode 100644 krita/plugins/filters/colorsfilters/kis_brightness_contrast_filter.cc create mode 100644 krita/plugins/filters/colorsfilters/kis_brightness_contrast_filter.h create mode 100644 krita/plugins/filters/colorsfilters/kis_perchannel_filter.cc create mode 100644 krita/plugins/filters/colorsfilters/kis_perchannel_filter.h create mode 100644 krita/plugins/filters/colorsfilters/kritacolorsfilter.desktop create mode 100644 krita/plugins/filters/colorsfilters/wdg_brightness_contrast.ui create mode 100644 krita/plugins/filters/colorsfilters/wdg_perchannel.ui create mode 100644 krita/plugins/filters/convolutionfilters/Makefile.am create mode 100644 krita/plugins/filters/convolutionfilters/convolutionfilters.cc create mode 100644 krita/plugins/filters/convolutionfilters/convolutionfilters.h create mode 100644 krita/plugins/filters/convolutionfilters/kis_convolution_filter.cc create mode 100644 krita/plugins/filters/convolutionfilters/kis_convolution_filter.h create mode 100644 krita/plugins/filters/convolutionfilters/kis_custom_convolution_filter.cc create mode 100644 krita/plugins/filters/convolutionfilters/kis_custom_convolution_filter.h create mode 100644 krita/plugins/filters/convolutionfilters/kis_custom_convolution_filter_configuration_base_widget.ui create mode 100644 krita/plugins/filters/convolutionfilters/kis_custom_convolution_filter_configuration_widget.cc create mode 100644 krita/plugins/filters/convolutionfilters/kis_custom_convolution_filter_configuration_widget.h create mode 100644 krita/plugins/filters/convolutionfilters/kritaconvolutionfilters.desktop create mode 100644 krita/plugins/filters/cubismfilter/Makefile.am create mode 100644 krita/plugins/filters/cubismfilter/kis_cubism_filter.cc create mode 100644 krita/plugins/filters/cubismfilter/kis_cubism_filter.h create mode 100644 krita/plugins/filters/cubismfilter/kis_cubism_filter_plugin.cc create mode 100644 krita/plugins/filters/cubismfilter/kis_cubism_filter_plugin.h create mode 100644 krita/plugins/filters/cubismfilter/kis_polygon.cc create mode 100644 krita/plugins/filters/cubismfilter/kis_polygon.h create mode 100644 krita/plugins/filters/cubismfilter/kritacubismfilter.desktop create mode 100644 krita/plugins/filters/embossfilter/Makefile.am create mode 100644 krita/plugins/filters/embossfilter/kis_emboss_filter.cc create mode 100644 krita/plugins/filters/embossfilter/kis_emboss_filter.h create mode 100644 krita/plugins/filters/embossfilter/kis_emboss_filter_plugin.cc create mode 100644 krita/plugins/filters/embossfilter/kis_emboss_filter_plugin.h create mode 100644 krita/plugins/filters/embossfilter/kritaembossfilter.desktop create mode 100644 krita/plugins/filters/example/Makefile.am create mode 100644 krita/plugins/filters/example/example.cc create mode 100644 krita/plugins/filters/example/example.h create mode 100644 krita/plugins/filters/example/kritaexample.desktop create mode 100644 krita/plugins/filters/fastcolortransfer/Makefile.am create mode 100644 krita/plugins/filters/fastcolortransfer/fastcolortransfer.cc create mode 100644 krita/plugins/filters/fastcolortransfer/fastcolortransfer.h create mode 100644 krita/plugins/filters/fastcolortransfer/kis_wdg_fastcolortransfer.cpp create mode 100644 krita/plugins/filters/fastcolortransfer/kis_wdg_fastcolortransfer.h create mode 100644 krita/plugins/filters/fastcolortransfer/kritafastcolortransfer.desktop create mode 100644 krita/plugins/filters/fastcolortransfer/wdgfastcolortransfer.ui create mode 100644 krita/plugins/filters/halftone/kis_halftone.cpp create mode 100644 krita/plugins/filters/halftone/kis_halftone.h create mode 100644 krita/plugins/filters/imageenhancement/Makefile.am create mode 100644 krita/plugins/filters/imageenhancement/imageenhancement.cpp create mode 100644 krita/plugins/filters/imageenhancement/imageenhancement.h create mode 100644 krita/plugins/filters/imageenhancement/kis_simple_noise_reducer.cpp create mode 100644 krita/plugins/filters/imageenhancement/kis_simple_noise_reducer.h create mode 100644 krita/plugins/filters/imageenhancement/kis_wavelet_noise_reduction.cpp create mode 100644 krita/plugins/filters/imageenhancement/kis_wavelet_noise_reduction.h create mode 100644 krita/plugins/filters/imageenhancement/kritaimageenhancement.desktop create mode 100644 krita/plugins/filters/lenscorrectionfilter/Makefile.am create mode 100644 krita/plugins/filters/lenscorrectionfilter/kis_wdg_lens_correction.cpp create mode 100644 krita/plugins/filters/lenscorrectionfilter/kis_wdg_lens_correction.h create mode 100644 krita/plugins/filters/lenscorrectionfilter/kritalenscorrectionfilter.desktop create mode 100644 krita/plugins/filters/lenscorrectionfilter/lenscorrectionfilter.cc create mode 100644 krita/plugins/filters/lenscorrectionfilter/lenscorrectionfilter.h create mode 100644 krita/plugins/filters/lenscorrectionfilter/wdglenscorrectionoptions.ui create mode 100644 krita/plugins/filters/levelfilter/Makefile.am create mode 100644 krita/plugins/filters/levelfilter/kgradientslider.cc create mode 100644 krita/plugins/filters/levelfilter/kgradientslider.h create mode 100644 krita/plugins/filters/levelfilter/kis_level_filter.cc create mode 100644 krita/plugins/filters/levelfilter/kis_level_filter.h create mode 100644 krita/plugins/filters/levelfilter/kritalevelfilter.desktop create mode 100644 krita/plugins/filters/levelfilter/levelfilter.cc create mode 100644 krita/plugins/filters/levelfilter/levelfilter.h create mode 100644 krita/plugins/filters/levelfilter/wdg_level.ui create mode 100644 krita/plugins/filters/noisefilter/Makefile.am create mode 100644 krita/plugins/filters/noisefilter/kis_wdg_noise.cpp create mode 100644 krita/plugins/filters/noisefilter/kis_wdg_noise.h create mode 100644 krita/plugins/filters/noisefilter/kritanoisefilter.desktop create mode 100644 krita/plugins/filters/noisefilter/noisefilter.cc create mode 100644 krita/plugins/filters/noisefilter/noisefilter.h create mode 100644 krita/plugins/filters/noisefilter/wdgnoiseoptions.ui create mode 100644 krita/plugins/filters/oilpaintfilter/Makefile.am create mode 100644 krita/plugins/filters/oilpaintfilter/kis_oilpaint_filter.cc create mode 100644 krita/plugins/filters/oilpaintfilter/kis_oilpaint_filter.h create mode 100644 krita/plugins/filters/oilpaintfilter/kis_oilpaint_filter_plugin.cc create mode 100644 krita/plugins/filters/oilpaintfilter/kis_oilpaint_filter_plugin.h create mode 100644 krita/plugins/filters/oilpaintfilter/kritaoilpaintfilter.desktop create mode 100644 krita/plugins/filters/pixelizefilter/Makefile.am create mode 100644 krita/plugins/filters/pixelizefilter/kis_pixelize_filter.cc create mode 100644 krita/plugins/filters/pixelizefilter/kis_pixelize_filter.h create mode 100644 krita/plugins/filters/pixelizefilter/kis_pixelize_filter_plugin.cc create mode 100644 krita/plugins/filters/pixelizefilter/kis_pixelize_filter_plugin.h create mode 100644 krita/plugins/filters/pixelizefilter/kritapixelizefilter.desktop create mode 100644 krita/plugins/filters/raindropsfilter/Makefile.am create mode 100644 krita/plugins/filters/raindropsfilter/kis_raindrops_filter.cc create mode 100644 krita/plugins/filters/raindropsfilter/kis_raindrops_filter.h create mode 100644 krita/plugins/filters/raindropsfilter/kis_raindrops_filter_plugin.cc create mode 100644 krita/plugins/filters/raindropsfilter/kis_raindrops_filter_plugin.h create mode 100644 krita/plugins/filters/raindropsfilter/kritaraindropsfilter.desktop create mode 100644 krita/plugins/filters/randompickfilter/Makefile.am create mode 100644 krita/plugins/filters/randompickfilter/kis_wdg_random_pick.cpp create mode 100644 krita/plugins/filters/randompickfilter/kis_wdg_random_pick.h create mode 100644 krita/plugins/filters/randompickfilter/kritarandompickfilter.desktop create mode 100644 krita/plugins/filters/randompickfilter/randompickfilter.cc create mode 100644 krita/plugins/filters/randompickfilter/randompickfilter.h create mode 100644 krita/plugins/filters/randompickfilter/wdgrandompickoptions.ui create mode 100644 krita/plugins/filters/roundcorners/Makefile.am create mode 100644 krita/plugins/filters/roundcorners/kis_round_corners_filter.cc create mode 100644 krita/plugins/filters/roundcorners/kis_round_corners_filter.h create mode 100644 krita/plugins/filters/roundcorners/kis_round_corners_filter_plugin.cc create mode 100644 krita/plugins/filters/roundcorners/kis_round_corners_filter_plugin.h create mode 100644 krita/plugins/filters/roundcorners/kritaroundcornersfilter.desktop create mode 100644 krita/plugins/filters/smalltilesfilter/Makefile.am create mode 100644 krita/plugins/filters/smalltilesfilter/kis_small_tiles_filter.cc create mode 100644 krita/plugins/filters/smalltilesfilter/kis_small_tiles_filter.h create mode 100644 krita/plugins/filters/smalltilesfilter/kis_small_tiles_filter_plugin.cc create mode 100644 krita/plugins/filters/smalltilesfilter/kis_small_tiles_filter_plugin.h create mode 100644 krita/plugins/filters/smalltilesfilter/kritasmalltilesfilter.desktop create mode 100644 krita/plugins/filters/sobelfilter/Makefile.am create mode 100644 krita/plugins/filters/sobelfilter/kis_sobel_filter.cc create mode 100644 krita/plugins/filters/sobelfilter/kis_sobel_filter.h create mode 100644 krita/plugins/filters/sobelfilter/kis_sobel_filter_plugin.cc create mode 100644 krita/plugins/filters/sobelfilter/kis_sobel_filter_plugin.h create mode 100644 krita/plugins/filters/sobelfilter/kritasobelfilter.desktop create mode 100644 krita/plugins/filters/threadtest/Makefile.am create mode 100644 krita/plugins/filters/threadtest/kritathreadtest.desktop create mode 100644 krita/plugins/filters/threadtest/threadtest.cc create mode 100644 krita/plugins/filters/threadtest/threadtest.h create mode 100644 krita/plugins/filters/unsharp/Makefile.am create mode 100644 krita/plugins/filters/unsharp/kis_unsharp_filter.cc create mode 100644 krita/plugins/filters/unsharp/kis_unsharp_filter.h create mode 100644 krita/plugins/filters/unsharp/kis_wdg_unsharp.cc create mode 100644 krita/plugins/filters/unsharp/kis_wdg_unsharp.h create mode 100644 krita/plugins/filters/unsharp/kritaunsharpfilter.desktop create mode 100644 krita/plugins/filters/unsharp/unsharp.cc create mode 100644 krita/plugins/filters/unsharp/unsharp.h create mode 100644 krita/plugins/filters/unsharp/wdgunsharp.ui create mode 100644 krita/plugins/filters/wavefilter/Makefile.am create mode 100644 krita/plugins/filters/wavefilter/kis_wdg_wave.cpp create mode 100644 krita/plugins/filters/wavefilter/kis_wdg_wave.h create mode 100644 krita/plugins/filters/wavefilter/kritawavefilter.desktop create mode 100644 krita/plugins/filters/wavefilter/wavefilter.cc create mode 100644 krita/plugins/filters/wavefilter/wavefilter.h create mode 100644 krita/plugins/filters/wavefilter/wdgwaveoptions.ui create mode 100644 krita/plugins/paintops/Makefile.am create mode 100644 krita/plugins/paintops/defaultpaintops/Makefile.am create mode 100644 krita/plugins/paintops/defaultpaintops/README create mode 100644 krita/plugins/paintops/defaultpaintops/airbrush.png create mode 100644 krita/plugins/paintops/defaultpaintops/defaultpaintops_plugin.cc create mode 100644 krita/plugins/paintops/defaultpaintops/defaultpaintops_plugin.h create mode 100644 krita/plugins/paintops/defaultpaintops/eraser.png create mode 100644 krita/plugins/paintops/defaultpaintops/kis_airbrushop.cc create mode 100644 krita/plugins/paintops/defaultpaintops/kis_airbrushop.h create mode 100644 krita/plugins/paintops/defaultpaintops/kis_brushop.cc create mode 100644 krita/plugins/paintops/defaultpaintops/kis_brushop.h create mode 100644 krita/plugins/paintops/defaultpaintops/kis_convolveop.cc create mode 100644 krita/plugins/paintops/defaultpaintops/kis_convolveop.h create mode 100644 krita/plugins/paintops/defaultpaintops/kis_dlgbrushcurvecontrol.ui create mode 100644 krita/plugins/paintops/defaultpaintops/kis_duplicateop.cc create mode 100644 krita/plugins/paintops/defaultpaintops/kis_duplicateop.h create mode 100644 krita/plugins/paintops/defaultpaintops/kis_eraseop.cc create mode 100644 krita/plugins/paintops/defaultpaintops/kis_eraseop.h create mode 100644 krita/plugins/paintops/defaultpaintops/kis_penop.cc create mode 100644 krita/plugins/paintops/defaultpaintops/kis_penop.h create mode 100644 krita/plugins/paintops/defaultpaintops/kis_smudgeop.cc create mode 100644 krita/plugins/paintops/defaultpaintops/kis_smudgeop.h create mode 100644 krita/plugins/paintops/defaultpaintops/kritadefaultpaintops.desktop create mode 100644 krita/plugins/paintops/defaultpaintops/paintbrush.png create mode 100644 krita/plugins/paintops/defaultpaintops/pencil.png create mode 100644 krita/plugins/paintops/defaultpaintops/src/README create mode 100644 krita/plugins/paintops/defaultpaintops/src/pencil_01.svg create mode 100644 krita/plugins/paintops/defaultpaintops/src/pencil_jonathan_dietrich_01.svg create mode 100644 krita/plugins/paintops/defaultpaintops/src/pennello_mauro_olivo_01.svg create mode 100644 krita/plugins/tools/Makefile.am create mode 100644 krita/plugins/tools/defaulttools/Makefile.am create mode 100644 krita/plugins/tools/defaulttools/closedhand_cursor.xpm create mode 100644 krita/plugins/tools/defaulttools/default_tools.cc create mode 100644 krita/plugins/tools/defaulttools/default_tools.h create mode 100644 krita/plugins/tools/defaulttools/kis_tool_brush.cc create mode 100644 krita/plugins/tools/defaulttools/kis_tool_brush.h create mode 100644 krita/plugins/tools/defaulttools/kis_tool_colorpicker.cc create mode 100644 krita/plugins/tools/defaulttools/kis_tool_colorpicker.h create mode 100644 krita/plugins/tools/defaulttools/kis_tool_duplicate.cc create mode 100644 krita/plugins/tools/defaulttools/kis_tool_duplicate.h create mode 100644 krita/plugins/tools/defaulttools/kis_tool_ellipse.cc create mode 100644 krita/plugins/tools/defaulttools/kis_tool_ellipse.h create mode 100644 krita/plugins/tools/defaulttools/kis_tool_fill.cc create mode 100644 krita/plugins/tools/defaulttools/kis_tool_fill.h create mode 100644 krita/plugins/tools/defaulttools/kis_tool_gradient.cc create mode 100644 krita/plugins/tools/defaulttools/kis_tool_gradient.h create mode 100644 krita/plugins/tools/defaulttools/kis_tool_line.cc create mode 100644 krita/plugins/tools/defaulttools/kis_tool_line.h create mode 100644 krita/plugins/tools/defaulttools/kis_tool_move.cc create mode 100644 krita/plugins/tools/defaulttools/kis_tool_move.h create mode 100644 krita/plugins/tools/defaulttools/kis_tool_pan.cc create mode 100644 krita/plugins/tools/defaulttools/kis_tool_pan.h create mode 100644 krita/plugins/tools/defaulttools/kis_tool_rectangle.cc create mode 100644 krita/plugins/tools/defaulttools/kis_tool_rectangle.h create mode 100644 krita/plugins/tools/defaulttools/kis_tool_text.cc create mode 100644 krita/plugins/tools/defaulttools/kis_tool_text.h create mode 100644 krita/plugins/tools/defaulttools/kis_tool_zoom.cc create mode 100644 krita/plugins/tools/defaulttools/kis_tool_zoom.h create mode 100644 krita/plugins/tools/defaulttools/kritadefaulttools.desktop create mode 100644 krita/plugins/tools/defaulttools/openhand_cursor.xpm create mode 100644 krita/plugins/tools/defaulttools/tool_color_fill.png create mode 100644 krita/plugins/tools/defaulttools/tool_colorpicker.png create mode 100644 krita/plugins/tools/defaulttools/tool_duplicate.png create mode 100644 krita/plugins/tools/defaulttools/tool_duplicate_cursor.png create mode 100644 krita/plugins/tools/defaulttools/tool_ellipse.png create mode 100644 krita/plugins/tools/defaulttools/tool_ellipse_cursor.png create mode 100644 krita/plugins/tools/defaulttools/tool_fill_cursor.png create mode 100644 krita/plugins/tools/defaulttools/tool_freehand.png create mode 100644 krita/plugins/tools/defaulttools/tool_freehand_cursor.png create mode 100644 krita/plugins/tools/defaulttools/tool_gradient.png create mode 100644 krita/plugins/tools/defaulttools/tool_gradient_cursor.png create mode 100644 krita/plugins/tools/defaulttools/tool_line.png create mode 100644 krita/plugins/tools/defaulttools/tool_line_cursor.png create mode 100644 krita/plugins/tools/defaulttools/tool_move.png create mode 100644 krita/plugins/tools/defaulttools/tool_pan.png create mode 100644 krita/plugins/tools/defaulttools/tool_rectangle.png create mode 100644 krita/plugins/tools/defaulttools/tool_rectangle_cursor.png create mode 100644 krita/plugins/tools/defaulttools/tool_text.png create mode 100644 krita/plugins/tools/defaulttools/tool_text_cursor.png create mode 100644 krita/plugins/tools/defaulttools/tool_zoom.png create mode 100644 krita/plugins/tools/defaulttools/tool_zoom_minus_cursor.png create mode 100644 krita/plugins/tools/defaulttools/tool_zoom_plus_cursor.png create mode 100644 krita/plugins/tools/defaulttools/wdgcolorpicker.ui create mode 100644 krita/plugins/tools/selectiontools/Makefile.am create mode 100644 krita/plugins/tools/selectiontools/kis_tool_move_selection.cc create mode 100644 krita/plugins/tools/selectiontools/kis_tool_move_selection.h create mode 100644 krita/plugins/tools/selectiontools/kis_tool_select_brush.cc create mode 100644 krita/plugins/tools/selectiontools/kis_tool_select_brush.h create mode 100644 krita/plugins/tools/selectiontools/kis_tool_select_contiguous.cc create mode 100644 krita/plugins/tools/selectiontools/kis_tool_select_contiguous.h create mode 100644 krita/plugins/tools/selectiontools/kis_tool_select_elliptical.cc create mode 100644 krita/plugins/tools/selectiontools/kis_tool_select_elliptical.h create mode 100644 krita/plugins/tools/selectiontools/kis_tool_select_eraser.cc create mode 100644 krita/plugins/tools/selectiontools/kis_tool_select_eraser.h create mode 100644 krita/plugins/tools/selectiontools/kis_tool_select_outline.cc create mode 100644 krita/plugins/tools/selectiontools/kis_tool_select_outline.h create mode 100644 krita/plugins/tools/selectiontools/kis_tool_select_polygonal.cc create mode 100644 krita/plugins/tools/selectiontools/kis_tool_select_polygonal.h create mode 100644 krita/plugins/tools/selectiontools/kis_tool_select_rectangular.cc create mode 100644 krita/plugins/tools/selectiontools/kis_tool_select_rectangular.h create mode 100644 krita/plugins/tools/selectiontools/kritaselectiontools.desktop create mode 100644 krita/plugins/tools/selectiontools/selection_tools.cc create mode 100644 krita/plugins/tools/selectiontools/selection_tools.h create mode 100644 krita/plugins/tools/selectiontools/tool_brush_selection.png create mode 100644 krita/plugins/tools/selectiontools/tool_brush_selection.svg create mode 100644 krita/plugins/tools/selectiontools/tool_brush_selection_cursor.png create mode 100644 krita/plugins/tools/selectiontools/tool_contiguous_selection.png create mode 100644 krita/plugins/tools/selectiontools/tool_contiguous_selection_cursor.png create mode 100644 krita/plugins/tools/selectiontools/tool_elliptical_selection.png create mode 100644 krita/plugins/tools/selectiontools/tool_elliptical_selection.svg create mode 100644 krita/plugins/tools/selectiontools/tool_elliptical_selection_cursor.png create mode 100644 krita/plugins/tools/selectiontools/tool_eraser_selection.png create mode 100644 krita/plugins/tools/selectiontools/tool_eraser_selection.svg create mode 100644 krita/plugins/tools/selectiontools/tool_eraser_selection_cursor.png create mode 100644 krita/plugins/tools/selectiontools/tool_outline_selection.png create mode 100644 krita/plugins/tools/selectiontools/tool_outline_selection.svg create mode 100644 krita/plugins/tools/selectiontools/tool_outline_selection_cursor.png create mode 100644 krita/plugins/tools/selectiontools/tool_polygonal_selection.png create mode 100644 krita/plugins/tools/selectiontools/tool_polygonal_selection.svg create mode 100644 krita/plugins/tools/selectiontools/tool_polygonal_selection_cursor.png create mode 100644 krita/plugins/tools/selectiontools/tool_rect_selection.png create mode 100644 krita/plugins/tools/selectiontools/tool_rect_selection.svg create mode 100644 krita/plugins/tools/selectiontools/tool_rectangular_selection_cursor.png create mode 100644 krita/plugins/tools/tool_crop/Makefile.am create mode 100644 krita/plugins/tools/tool_crop/kis_tool_crop.cc create mode 100644 krita/plugins/tools/tool_crop/kis_tool_crop.h create mode 100644 krita/plugins/tools/tool_crop/kritatoolcrop.desktop create mode 100644 krita/plugins/tools/tool_crop/tool_crop.cc create mode 100644 krita/plugins/tools/tool_crop/tool_crop.h create mode 100644 krita/plugins/tools/tool_crop/tool_crop.png create mode 100644 krita/plugins/tools/tool_crop/tool_crop_cursor.png create mode 100644 krita/plugins/tools/tool_crop/wdg_tool_crop.ui create mode 100644 krita/plugins/tools/tool_curves/Makefile.am create mode 100644 krita/plugins/tools/tool_curves/kis_curve_framework.cc create mode 100644 krita/plugins/tools/tool_curves/kis_curve_framework.h create mode 100644 krita/plugins/tools/tool_curves/kis_tool_bezier.cc create mode 100644 krita/plugins/tools/tool_curves/kis_tool_bezier.h create mode 100644 krita/plugins/tools/tool_curves/kis_tool_bezier_paint.cc create mode 100644 krita/plugins/tools/tool_curves/kis_tool_bezier_paint.h create mode 100644 krita/plugins/tools/tool_curves/kis_tool_bezier_select.cc create mode 100644 krita/plugins/tools/tool_curves/kis_tool_bezier_select.h create mode 100644 krita/plugins/tools/tool_curves/kis_tool_curve.cc create mode 100644 krita/plugins/tools/tool_curves/kis_tool_curve.h create mode 100644 krita/plugins/tools/tool_curves/kis_tool_example.cc create mode 100644 krita/plugins/tools/tool_curves/kis_tool_example.h create mode 100644 krita/plugins/tools/tool_curves/kis_tool_moutline.cc create mode 100644 krita/plugins/tools/tool_curves/kis_tool_moutline.h create mode 100644 krita/plugins/tools/tool_curves/kritatoolcurves.desktop create mode 100644 krita/plugins/tools/tool_curves/tool_bezier_cursor.png create mode 100644 krita/plugins/tools/tool_curves/tool_bezier_paint.png create mode 100644 krita/plugins/tools/tool_curves/tool_bezier_select.png create mode 100644 krita/plugins/tools/tool_curves/tool_curve_dragging.png create mode 100644 krita/plugins/tools/tool_curves/tool_curves.cc create mode 100644 krita/plugins/tools/tool_curves/tool_curves.h create mode 100644 krita/plugins/tools/tool_curves/tool_example.png create mode 100644 krita/plugins/tools/tool_curves/tool_example_cursor.png create mode 100644 krita/plugins/tools/tool_curves/tool_moutline.png create mode 100644 krita/plugins/tools/tool_curves/tool_moutline_cursor.png create mode 100644 krita/plugins/tools/tool_curves/tool_moutline_editing.png create mode 100644 krita/plugins/tools/tool_curves/wdg_tool_example.ui create mode 100644 krita/plugins/tools/tool_filter/Makefile.am create mode 100644 krita/plugins/tools/tool_filter/kis_filterop.cc create mode 100644 krita/plugins/tools/tool_filter/kis_filterop.h create mode 100644 krita/plugins/tools/tool_filter/kis_tool_filter.cc create mode 100644 krita/plugins/tools/tool_filter/kis_tool_filter.h create mode 100644 krita/plugins/tools/tool_filter/kritatoolfilter.desktop create mode 100644 krita/plugins/tools/tool_filter/tool_filter.cc create mode 100644 krita/plugins/tools/tool_filter/tool_filter.h create mode 100644 krita/plugins/tools/tool_filter/tool_filter.png create mode 100644 krita/plugins/tools/tool_filter/tool_filter.svg create mode 100644 krita/plugins/tools/tool_filter/tool_filter_cursor.png create mode 100644 krita/plugins/tools/tool_perspectivegrid/Makefile.am create mode 100644 krita/plugins/tools/tool_perspectivegrid/kis_tool_perspectivegrid.cc create mode 100644 krita/plugins/tools/tool_perspectivegrid/kis_tool_perspectivegrid.h create mode 100644 krita/plugins/tools/tool_perspectivegrid/kritatoolperspectivegrid.desktop create mode 100644 krita/plugins/tools/tool_perspectivegrid/tool_perspectivegrid.cc create mode 100644 krita/plugins/tools/tool_perspectivegrid/tool_perspectivegrid.h create mode 100644 krita/plugins/tools/tool_perspectivegrid/tool_perspectivegrid.png create mode 100644 krita/plugins/tools/tool_perspectivegrid/tool_perspectivegrid.svg create mode 100644 krita/plugins/tools/tool_perspectivetransform/Makefile.am create mode 100644 krita/plugins/tools/tool_perspectivetransform/kis_tool_perspectivetransform.cc create mode 100644 krita/plugins/tools/tool_perspectivetransform/kis_tool_perspectivetransform.h create mode 100644 krita/plugins/tools/tool_perspectivetransform/kritatoolperspectivetransform.desktop create mode 100644 krita/plugins/tools/tool_perspectivetransform/tool_perspectivetransform.cc create mode 100644 krita/plugins/tools/tool_perspectivetransform/tool_perspectivetransform.h create mode 100644 krita/plugins/tools/tool_perspectivetransform/tool_perspectivetransform.png create mode 100644 krita/plugins/tools/tool_perspectivetransform/tool_perspectivetransform.svg create mode 100644 krita/plugins/tools/tool_polygon/Makefile.am create mode 100644 krita/plugins/tools/tool_polygon/kis_tool_polygon.cc create mode 100644 krita/plugins/tools/tool_polygon/kis_tool_polygon.h create mode 100644 krita/plugins/tools/tool_polygon/kritatoolpolygon.desktop create mode 100644 krita/plugins/tools/tool_polygon/tool_polygon.cc create mode 100644 krita/plugins/tools/tool_polygon/tool_polygon.h create mode 100644 krita/plugins/tools/tool_polygon/tool_polygon.png create mode 100644 krita/plugins/tools/tool_polygon/tool_polygon_cursor.png create mode 100644 krita/plugins/tools/tool_polyline/Makefile.am create mode 100644 krita/plugins/tools/tool_polyline/kis_tool_polyline.cc create mode 100644 krita/plugins/tools/tool_polyline/kis_tool_polyline.h create mode 100644 krita/plugins/tools/tool_polyline/kritatoolpolyline.desktop create mode 100644 krita/plugins/tools/tool_polyline/polyline.png create mode 100644 krita/plugins/tools/tool_polyline/tool_polyline.cc create mode 100644 krita/plugins/tools/tool_polyline/tool_polyline.h create mode 100644 krita/plugins/tools/tool_polyline/tool_polyline_cursor.png create mode 100644 krita/plugins/tools/tool_selectsimilar/Makefile.am create mode 100644 krita/plugins/tools/tool_selectsimilar/kis_tool_selectsimilar.cc create mode 100644 krita/plugins/tools/tool_selectsimilar/kis_tool_selectsimilar.h create mode 100644 krita/plugins/tools/tool_selectsimilar/kritatoolselectsimilar.desktop create mode 100644 krita/plugins/tools/tool_selectsimilar/selectsimilar.cc create mode 100644 krita/plugins/tools/tool_selectsimilar/selectsimilar.h create mode 100644 krita/plugins/tools/tool_selectsimilar/tool_similar_selection.png create mode 100644 krita/plugins/tools/tool_selectsimilar/tool_similar_selection.svg create mode 100644 krita/plugins/tools/tool_selectsimilar/tool_similar_selection_minus_cursor.png create mode 100644 krita/plugins/tools/tool_selectsimilar/tool_similar_selection_plus_cursor.png create mode 100644 krita/plugins/tools/tool_star/Makefile.am create mode 100644 krita/plugins/tools/tool_star/kis_tool_star.cc create mode 100644 krita/plugins/tools/tool_star/kis_tool_star.h create mode 100644 krita/plugins/tools/tool_star/kritatoolstar.desktop create mode 100644 krita/plugins/tools/tool_star/tool_star.cc create mode 100644 krita/plugins/tools/tool_star/tool_star.h create mode 100644 krita/plugins/tools/tool_star/tool_star.png create mode 100644 krita/plugins/tools/tool_star/tool_star_cursor.png create mode 100644 krita/plugins/tools/tool_star/wdg_tool_star.ui create mode 100644 krita/plugins/tools/tool_transform/Makefile.am create mode 100644 krita/plugins/tools/tool_transform/kis_tool_transform.cc create mode 100644 krita/plugins/tools/tool_transform/kis_tool_transform.h create mode 100644 krita/plugins/tools/tool_transform/kritatooltransform.desktop create mode 100644 krita/plugins/tools/tool_transform/rotate_cursor.xpm create mode 100644 krita/plugins/tools/tool_transform/tool_transform.cc create mode 100644 krita/plugins/tools/tool_transform/tool_transform.h create mode 100644 krita/plugins/tools/tool_transform/tool_transform.png create mode 100644 krita/plugins/tools/tool_transform/wdg_tool_transform.ui create mode 100644 krita/plugins/viewplugins/Makefile.am create mode 100644 krita/plugins/viewplugins/colorrange/Makefile.am create mode 100644 krita/plugins/viewplugins/colorrange/colorrange.cc create mode 100644 krita/plugins/viewplugins/colorrange/colorrange.h create mode 100644 krita/plugins/viewplugins/colorrange/colorrange.rc create mode 100644 krita/plugins/viewplugins/colorrange/dlg_colorrange.cc create mode 100644 krita/plugins/viewplugins/colorrange/dlg_colorrange.h create mode 100644 krita/plugins/viewplugins/colorrange/kritacolorrange.desktop create mode 100644 krita/plugins/viewplugins/colorrange/wdg_colorrange.ui create mode 100644 krita/plugins/viewplugins/colorspaceconversion/Makefile.am create mode 100644 krita/plugins/viewplugins/colorspaceconversion/colorspaceconversion.cc create mode 100644 krita/plugins/viewplugins/colorspaceconversion/colorspaceconversion.h create mode 100644 krita/plugins/viewplugins/colorspaceconversion/colorspaceconversion.rc create mode 100644 krita/plugins/viewplugins/colorspaceconversion/dlg_colorspaceconversion.cc create mode 100644 krita/plugins/viewplugins/colorspaceconversion/dlg_colorspaceconversion.h create mode 100644 krita/plugins/viewplugins/colorspaceconversion/kritacolorspaceconversion.desktop create mode 100644 krita/plugins/viewplugins/colorspaceconversion/wdgconvertcolorspace.ui create mode 100644 krita/plugins/viewplugins/dropshadow/Makefile.am create mode 100644 krita/plugins/viewplugins/dropshadow/dlg_dropshadow.cc create mode 100644 krita/plugins/viewplugins/dropshadow/dlg_dropshadow.h create mode 100644 krita/plugins/viewplugins/dropshadow/dropshadow.rc create mode 100644 krita/plugins/viewplugins/dropshadow/kis_dropshadow.cc create mode 100644 krita/plugins/viewplugins/dropshadow/kis_dropshadow.h create mode 100644 krita/plugins/viewplugins/dropshadow/kis_dropshadow_plugin.cc create mode 100644 krita/plugins/viewplugins/dropshadow/kis_dropshadow_plugin.h create mode 100644 krita/plugins/viewplugins/dropshadow/kritadropshadow.desktop create mode 100644 krita/plugins/viewplugins/dropshadow/wdg_dropshadow.ui create mode 100644 krita/plugins/viewplugins/filtersgallery/Makefile.am create mode 100644 krita/plugins/viewplugins/filtersgallery/filters_gallery.cc create mode 100644 krita/plugins/viewplugins/filtersgallery/filters_gallery.h create mode 100644 krita/plugins/viewplugins/filtersgallery/kis_dlg_filtersgallery.cc create mode 100644 krita/plugins/viewplugins/filtersgallery/kis_dlg_filtersgallery.h create mode 100644 krita/plugins/viewplugins/filtersgallery/kis_wdg_filtersgallery.ui create mode 100644 krita/plugins/viewplugins/filtersgallery/kritafiltersgallery.desktop create mode 100644 krita/plugins/viewplugins/filtersgallery/kritafiltersgallery.rc create mode 100644 krita/plugins/viewplugins/histogram/Makefile.am create mode 100644 krita/plugins/viewplugins/histogram/dlg_histogram.cc create mode 100644 krita/plugins/viewplugins/histogram/dlg_histogram.h create mode 100644 krita/plugins/viewplugins/histogram/histogram.cc create mode 100644 krita/plugins/viewplugins/histogram/histogram.h create mode 100644 krita/plugins/viewplugins/histogram/histogram.rc create mode 100644 krita/plugins/viewplugins/histogram/kis_histogram_widget.cc create mode 100644 krita/plugins/viewplugins/histogram/kis_histogram_widget.h create mode 100644 krita/plugins/viewplugins/histogram/kritahistogram.desktop create mode 100644 krita/plugins/viewplugins/histogram/wdghistogram.ui create mode 100644 krita/plugins/viewplugins/histogram_docker/Makefile.am create mode 100644 krita/plugins/viewplugins/histogram_docker/histogramdocker.cc create mode 100644 krita/plugins/viewplugins/histogram_docker/histogramdocker.h create mode 100644 krita/plugins/viewplugins/histogram_docker/kis_accumulating_producer.cc create mode 100644 krita/plugins/viewplugins/histogram_docker/kis_accumulating_producer.h create mode 100644 krita/plugins/viewplugins/histogram_docker/kis_cachedhistogram.cc create mode 100644 krita/plugins/viewplugins/histogram_docker/kis_cachedhistogram.h create mode 100644 krita/plugins/viewplugins/histogram_docker/kis_imagerasteredcache.cc create mode 100644 krita/plugins/viewplugins/histogram_docker/kis_imagerasteredcache.h create mode 100644 krita/plugins/viewplugins/histogram_docker/kritahistogramdocker.desktop create mode 100644 krita/plugins/viewplugins/histogram_docker/kritahistogramdocker.rc create mode 100644 krita/plugins/viewplugins/history_docker/Makefile.am create mode 100644 krita/plugins/viewplugins/history_docker/historydocker.cc create mode 100644 krita/plugins/viewplugins/history_docker/historydocker.h create mode 100644 krita/plugins/viewplugins/history_docker/kritahistorydocker.desktop create mode 100644 krita/plugins/viewplugins/imagesize/Makefile.am create mode 100644 krita/plugins/viewplugins/imagesize/configure.in.in create mode 100644 krita/plugins/viewplugins/imagesize/dlg_imagesize.cc create mode 100644 krita/plugins/viewplugins/imagesize/dlg_imagesize.h create mode 100644 krita/plugins/viewplugins/imagesize/dlg_layersize.cc create mode 100644 krita/plugins/viewplugins/imagesize/dlg_layersize.h create mode 100644 krita/plugins/viewplugins/imagesize/imagesize.cc create mode 100644 krita/plugins/viewplugins/imagesize/imagesize.h create mode 100644 krita/plugins/viewplugins/imagesize/imagesize.rc create mode 100644 krita/plugins/viewplugins/imagesize/kritaimagesize.desktop create mode 100644 krita/plugins/viewplugins/imagesize/wdg_imagesize.ui create mode 100644 krita/plugins/viewplugins/imagesize/wdg_layersize.ui create mode 100644 krita/plugins/viewplugins/imagesize/wdg_resolution.ui create mode 100644 krita/plugins/viewplugins/modify_selection/Makefile.am create mode 100644 krita/plugins/viewplugins/modify_selection/dlg_border_selection.cc create mode 100644 krita/plugins/viewplugins/modify_selection/dlg_border_selection.h create mode 100644 krita/plugins/viewplugins/modify_selection/dlg_grow_selection.cc create mode 100644 krita/plugins/viewplugins/modify_selection/dlg_grow_selection.h create mode 100644 krita/plugins/viewplugins/modify_selection/dlg_shrink_selection.cc create mode 100644 krita/plugins/viewplugins/modify_selection/dlg_shrink_selection.h create mode 100644 krita/plugins/viewplugins/modify_selection/kritamodifyselection.desktop create mode 100644 krita/plugins/viewplugins/modify_selection/modify_selection.cc create mode 100644 krita/plugins/viewplugins/modify_selection/modify_selection.h create mode 100644 krita/plugins/viewplugins/modify_selection/modify_selection.rc create mode 100644 krita/plugins/viewplugins/modify_selection/wdg_border_selection.ui create mode 100644 krita/plugins/viewplugins/modify_selection/wdg_grow_selection.ui create mode 100644 krita/plugins/viewplugins/modify_selection/wdg_shrink_selection.ui create mode 100644 krita/plugins/viewplugins/performancetest/Makefile.am create mode 100644 krita/plugins/viewplugins/performancetest/dlg_perftest.cc create mode 100644 krita/plugins/viewplugins/performancetest/dlg_perftest.h create mode 100644 krita/plugins/viewplugins/performancetest/kritaperftest.desktop create mode 100644 krita/plugins/viewplugins/performancetest/perftest.cc create mode 100644 krita/plugins/viewplugins/performancetest/perftest.h create mode 100644 krita/plugins/viewplugins/performancetest/perftest.rc create mode 100644 krita/plugins/viewplugins/performancetest/wdg_perftest.ui create mode 100644 krita/plugins/viewplugins/rotateimage/Makefile.am create mode 100644 krita/plugins/viewplugins/rotateimage/dlg_rotateimage.cc create mode 100644 krita/plugins/viewplugins/rotateimage/dlg_rotateimage.h create mode 100644 krita/plugins/viewplugins/rotateimage/kritarotateimage.desktop create mode 100644 krita/plugins/viewplugins/rotateimage/rotateimage.cc create mode 100644 krita/plugins/viewplugins/rotateimage/rotateimage.h create mode 100644 krita/plugins/viewplugins/rotateimage/rotateimage.rc create mode 100644 krita/plugins/viewplugins/rotateimage/wdg_rotateimage.ui create mode 100644 krita/plugins/viewplugins/screenshot/Makefile.am create mode 100644 krita/plugins/viewplugins/screenshot/kritascreenshot.desktop create mode 100644 krita/plugins/viewplugins/screenshot/ksnapshot.cpp create mode 100644 krita/plugins/viewplugins/screenshot/ksnapshot.h create mode 100644 krita/plugins/viewplugins/screenshot/ksnapshotwidget.ui create mode 100644 krita/plugins/viewplugins/screenshot/ksnapshotwidget.ui.h create mode 100644 krita/plugins/viewplugins/screenshot/main.cpp create mode 100644 krita/plugins/viewplugins/screenshot/regiongrabber.cpp create mode 100644 krita/plugins/viewplugins/screenshot/regiongrabber.h create mode 100644 krita/plugins/viewplugins/screenshot/screenshot-kpresenter.rc create mode 100644 krita/plugins/viewplugins/screenshot/screenshot-krita.rc create mode 100644 krita/plugins/viewplugins/screenshot/screenshot-kword.rc create mode 100644 krita/plugins/viewplugins/screenshot/screenshot.cpp create mode 100644 krita/plugins/viewplugins/screenshot/screenshot.h create mode 100644 krita/plugins/viewplugins/scripting/Makefile.am create mode 100644 krita/plugins/viewplugins/scripting/kritacore/Makefile.am create mode 100644 krita/plugins/viewplugins/scripting/kritacore/kritacoremodule.cpp create mode 100644 krita/plugins/viewplugins/scripting/kritacore/kritacoremodule.h create mode 100644 krita/plugins/viewplugins/scripting/kritacore/krs_brush.cpp create mode 100644 krita/plugins/viewplugins/scripting/kritacore/krs_brush.h create mode 100644 krita/plugins/viewplugins/scripting/kritacore/krs_color.cpp create mode 100644 krita/plugins/viewplugins/scripting/kritacore/krs_color.h create mode 100644 krita/plugins/viewplugins/scripting/kritacore/krs_doc.cpp create mode 100644 krita/plugins/viewplugins/scripting/kritacore/krs_doc.h create mode 100644 krita/plugins/viewplugins/scripting/kritacore/krs_filter.cpp create mode 100644 krita/plugins/viewplugins/scripting/kritacore/krs_filter.h create mode 100644 krita/plugins/viewplugins/scripting/kritacore/krs_filter_configuration.cpp create mode 100644 krita/plugins/viewplugins/scripting/kritacore/krs_filter_configuration.h create mode 100644 krita/plugins/viewplugins/scripting/kritacore/krs_histogram.cpp create mode 100644 krita/plugins/viewplugins/scripting/kritacore/krs_histogram.h create mode 100644 krita/plugins/viewplugins/scripting/kritacore/krs_image.cpp create mode 100644 krita/plugins/viewplugins/scripting/kritacore/krs_image.h create mode 100644 krita/plugins/viewplugins/scripting/kritacore/krs_iterator.h create mode 100644 krita/plugins/viewplugins/scripting/kritacore/krs_paint_layer.cpp create mode 100644 krita/plugins/viewplugins/scripting/kritacore/krs_paint_layer.h create mode 100644 krita/plugins/viewplugins/scripting/kritacore/krs_painter.cpp create mode 100644 krita/plugins/viewplugins/scripting/kritacore/krs_painter.h create mode 100644 krita/plugins/viewplugins/scripting/kritacore/krs_pattern.cpp create mode 100644 krita/plugins/viewplugins/scripting/kritacore/krs_pattern.h create mode 100644 krita/plugins/viewplugins/scripting/kritacore/krs_script_progress.cpp create mode 100644 krita/plugins/viewplugins/scripting/kritacore/krs_script_progress.h create mode 100644 krita/plugins/viewplugins/scripting/kritacore/krs_wavelet.cpp create mode 100644 krita/plugins/viewplugins/scripting/kritacore/krs_wavelet.h create mode 100644 krita/plugins/viewplugins/scripting/kritascripting.desktop create mode 100644 krita/plugins/viewplugins/scripting/kritascripting/Makefile.am create mode 100644 krita/plugins/viewplugins/scripting/kritascripting/kis_script_monitor.cpp create mode 100644 krita/plugins/viewplugins/scripting/kritascripting/kis_script_monitor.h create mode 100644 krita/plugins/viewplugins/scripting/kritascripting/kis_script_progress.cpp create mode 100644 krita/plugins/viewplugins/scripting/kritascripting/kis_script_progress.h create mode 100644 krita/plugins/viewplugins/scripting/samples/Makefile.am create mode 100644 krita/plugins/viewplugins/scripting/samples/python/Makefile.am create mode 100644 krita/plugins/viewplugins/scripting/samples/python/invert.py create mode 100644 krita/plugins/viewplugins/scripting/samples/python/invertpython.rc create mode 100644 krita/plugins/viewplugins/scripting/samples/python/reshapehisto.py create mode 100644 krita/plugins/viewplugins/scripting/samples/python/reshapehisto.rc create mode 100644 krita/plugins/viewplugins/scripting/samples/ruby/Makefile.am create mode 100644 krita/plugins/viewplugins/scripting/samples/ruby/changecs.rb create mode 100644 krita/plugins/viewplugins/scripting/samples/ruby/changecs.rc create mode 100644 krita/plugins/viewplugins/scripting/samples/ruby/filterstest.rb create mode 100644 krita/plugins/viewplugins/scripting/samples/ruby/filterstest.rc create mode 100644 krita/plugins/viewplugins/scripting/samples/ruby/invert.rb create mode 100644 krita/plugins/viewplugins/scripting/samples/ruby/invertruby.rc create mode 100644 krita/plugins/viewplugins/scripting/samples/ruby/randompaint.rb create mode 100644 krita/plugins/viewplugins/scripting/samples/ruby/randompaint.rc create mode 100644 krita/plugins/viewplugins/scripting/samples/ruby/torture-filters.rb create mode 100644 krita/plugins/viewplugins/scripting/samples/ruby/torture-filters.rc create mode 100644 krita/plugins/viewplugins/scripting/samples/ruby/torture-painting.rb create mode 100644 krita/plugins/viewplugins/scripting/samples/ruby/torture-painting.rc create mode 100644 krita/plugins/viewplugins/scripting/scripting.cc create mode 100644 krita/plugins/viewplugins/scripting/scripting.h create mode 100644 krita/plugins/viewplugins/scripting/scripting.rc create mode 100644 krita/plugins/viewplugins/selectopaque/Makefile.am create mode 100644 krita/plugins/viewplugins/selectopaque/kritaselectopaque.desktop create mode 100644 krita/plugins/viewplugins/selectopaque/selectopaque.cc create mode 100644 krita/plugins/viewplugins/selectopaque/selectopaque.h create mode 100644 krita/plugins/viewplugins/selectopaque/selectopaque.rc create mode 100644 krita/plugins/viewplugins/separate_channels/Makefile.am create mode 100644 krita/plugins/viewplugins/separate_channels/dlg_separate.cc create mode 100644 krita/plugins/viewplugins/separate_channels/dlg_separate.h create mode 100644 krita/plugins/viewplugins/separate_channels/imageseparate.rc create mode 100644 krita/plugins/viewplugins/separate_channels/kis_channel_separator.cc create mode 100644 krita/plugins/viewplugins/separate_channels/kis_channel_separator.h create mode 100644 krita/plugins/viewplugins/separate_channels/kis_separate_channels_plugin.cc create mode 100644 krita/plugins/viewplugins/separate_channels/kis_separate_channels_plugin.h create mode 100644 krita/plugins/viewplugins/separate_channels/kritaseparatechannels.desktop create mode 100644 krita/plugins/viewplugins/separate_channels/wdg_separations.ui create mode 100644 krita/plugins/viewplugins/shearimage/Makefile.am create mode 100644 krita/plugins/viewplugins/shearimage/dlg_shearimage.cc create mode 100644 krita/plugins/viewplugins/shearimage/dlg_shearimage.h create mode 100644 krita/plugins/viewplugins/shearimage/kritashearimage.desktop create mode 100644 krita/plugins/viewplugins/shearimage/shearimage.cc create mode 100644 krita/plugins/viewplugins/shearimage/shearimage.h create mode 100644 krita/plugins/viewplugins/shearimage/shearimage.rc create mode 100644 krita/plugins/viewplugins/shearimage/wdg_shearimage.ui create mode 100644 krita/plugins/viewplugins/substrate/Makefile.am create mode 100644 krita/plugins/viewplugins/substrate/dlg_substrate.cc create mode 100644 krita/plugins/viewplugins/substrate/dlg_substrate.h create mode 100644 krita/plugins/viewplugins/substrate/kis_repeating_substrate.cc create mode 100644 krita/plugins/viewplugins/substrate/kis_repeating_substrate.h create mode 100644 krita/plugins/viewplugins/substrate/kritasubstrate.desktop create mode 100644 krita/plugins/viewplugins/substrate/substrate.cc create mode 100644 krita/plugins/viewplugins/substrate/substrate.h create mode 100644 krita/plugins/viewplugins/substrate/substrate.rc create mode 100644 krita/plugins/viewplugins/substrate/wdgsubstrate.ui create mode 100644 krita/plugins/viewplugins/variations/Makefile.am create mode 100644 krita/plugins/viewplugins/variations/dlg_variations.cc create mode 100644 krita/plugins/viewplugins/variations/dlg_variations.h create mode 100644 krita/plugins/viewplugins/variations/kritavariations.desktop create mode 100644 krita/plugins/viewplugins/variations/variations.cc create mode 100644 krita/plugins/viewplugins/variations/variations.h create mode 100644 krita/plugins/viewplugins/variations/variations.rc create mode 100644 krita/plugins/viewplugins/variations/wdg_variations.ui create mode 100644 krita/sdk/Makefile.am create mode 100644 krita/sdk/kis_annotation.h create mode 100644 krita/sdk/kis_canvas_controller.h create mode 100644 krita/sdk/kis_canvas_observer.h create mode 100644 krita/sdk/kis_canvas_subject.h create mode 100644 krita/sdk/kis_debug_areas.h create mode 100644 krita/sdk/kis_generic_registry.h create mode 100644 krita/sdk/kis_global.h create mode 100644 krita/sdk/kis_id.h create mode 100644 krita/sdk/kis_integer_maths.h create mode 100644 krita/sdk/kis_progress_display_interface.h create mode 100644 krita/sdk/kis_progress_subject.cc create mode 100644 krita/sdk/kis_progress_subject.h create mode 100644 krita/sdk/kis_shared_ptr_vector.h create mode 100644 krita/sdk/kis_undo_adapter.h create mode 100644 krita/todo-1.6 create mode 100644 krita/ui/Makefile.am create mode 100644 krita/ui/imageviewer.cc create mode 100644 krita/ui/imageviewer.h create mode 100644 krita/ui/kcurve.cc create mode 100644 krita/ui/kcurve.h create mode 100644 krita/ui/kis_aboutdata.h create mode 100644 krita/ui/kis_autobrush.cc create mode 100644 krita/ui/kis_autobrush.h create mode 100644 krita/ui/kis_autogradient.cc create mode 100644 krita/ui/kis_autogradient.h create mode 100644 krita/ui/kis_birdeye_box.cc create mode 100644 krita/ui/kis_birdeye_box.h create mode 100644 krita/ui/kis_boundary_painter.cc create mode 100644 krita/ui/kis_boundary_painter.h create mode 100644 krita/ui/kis_brush_chooser.cc create mode 100644 krita/ui/kis_brush_chooser.h create mode 100644 krita/ui/kis_button_event.h create mode 100644 krita/ui/kis_button_press_event.h create mode 100644 krita/ui/kis_button_release_event.h create mode 100644 krita/ui/kis_canvas.cc create mode 100644 krita/ui/kis_canvas.h create mode 100644 krita/ui/kis_canvas_painter.cc create mode 100644 krita/ui/kis_canvas_painter.h create mode 100644 krita/ui/kis_clipboard.cc create mode 100644 krita/ui/kis_clipboard.h create mode 100644 krita/ui/kis_cmb_composite.cc create mode 100644 krita/ui/kis_cmb_composite.h create mode 100644 krita/ui/kis_cmb_idlist.cc create mode 100644 krita/ui/kis_cmb_idlist.h create mode 100644 krita/ui/kis_color_cup.cc create mode 100644 krita/ui/kis_color_cup.h create mode 100644 krita/ui/kis_config.cc create mode 100644 krita/ui/kis_config.h create mode 100644 krita/ui/kis_controlframe.cc create mode 100644 krita/ui/kis_controlframe.h create mode 100644 krita/ui/kis_cursor.cc create mode 100644 krita/ui/kis_cursor.h create mode 100644 krita/ui/kis_custom_brush.cc create mode 100644 krita/ui/kis_custom_brush.h create mode 100644 krita/ui/kis_custom_image_widget.cc create mode 100644 krita/ui/kis_custom_image_widget.h create mode 100644 krita/ui/kis_custom_palette.cc create mode 100644 krita/ui/kis_custom_palette.h create mode 100644 krita/ui/kis_custom_pattern.cc create mode 100644 krita/ui/kis_custom_pattern.h create mode 100644 krita/ui/kis_dlg_adj_layer_props.cc create mode 100644 krita/ui/kis_dlg_adj_layer_props.h create mode 100644 krita/ui/kis_dlg_adjustment_layer.cc create mode 100644 krita/ui/kis_dlg_adjustment_layer.h create mode 100644 krita/ui/kis_dlg_apply_profile.cc create mode 100644 krita/ui/kis_dlg_apply_profile.h create mode 100644 krita/ui/kis_dlg_image_properties.cc create mode 100644 krita/ui/kis_dlg_image_properties.h create mode 100644 krita/ui/kis_dlg_layer_properties.cc create mode 100644 krita/ui/kis_dlg_layer_properties.h create mode 100644 krita/ui/kis_dlg_new_layer.cc create mode 100644 krita/ui/kis_dlg_new_layer.h create mode 100644 krita/ui/kis_dlg_preferences.cc create mode 100644 krita/ui/kis_dlg_preferences.h create mode 100644 krita/ui/kis_doc.cc create mode 100644 krita/ui/kis_doc.h create mode 100644 krita/ui/kis_doc_iface.cc create mode 100644 krita/ui/kis_doc_iface.h create mode 100644 krita/ui/kis_double_click_event.h create mode 100644 krita/ui/kis_double_widget.cc create mode 100644 krita/ui/kis_double_widget.h create mode 100644 krita/ui/kis_event.h create mode 100644 krita/ui/kis_factory.cc create mode 100644 krita/ui/kis_factory.h create mode 100644 krita/ui/kis_filter_manager.cc create mode 100644 krita/ui/kis_filter_manager.h create mode 100644 krita/ui/kis_filters_listview.cc create mode 100644 krita/ui/kis_filters_listview.h create mode 100644 krita/ui/kis_gradient_chooser.cc create mode 100644 krita/ui/kis_gradient_chooser.h create mode 100644 krita/ui/kis_gradient_slider_widget.cc create mode 100644 krita/ui/kis_gradient_slider_widget.h create mode 100644 krita/ui/kis_grid_drawer.cpp create mode 100644 krita/ui/kis_grid_drawer.h create mode 100644 krita/ui/kis_grid_manager.cpp create mode 100644 krita/ui/kis_grid_manager.h create mode 100644 krita/ui/kis_histogram_view.cc create mode 100644 krita/ui/kis_histogram_view.h create mode 100644 krita/ui/kis_icon_item.cc create mode 100644 krita/ui/kis_icon_item.h create mode 100644 krita/ui/kis_iconwidget.cc create mode 100644 krita/ui/kis_iconwidget.h create mode 100644 krita/ui/kis_import_catcher.cc create mode 100644 krita/ui/kis_import_catcher.h create mode 100644 krita/ui/kis_input_device.cc create mode 100644 krita/ui/kis_input_device.h create mode 100644 krita/ui/kis_int_spinbox.cc create mode 100644 krita/ui/kis_int_spinbox.h create mode 100644 krita/ui/kis_itemchooser.cc create mode 100644 krita/ui/kis_itemchooser.h create mode 100644 krita/ui/kis_label_cursor_pos.cc create mode 100644 krita/ui/kis_label_cursor_pos.h create mode 100644 krita/ui/kis_label_progress.cc create mode 100644 krita/ui/kis_label_progress.h create mode 100644 krita/ui/kis_label_zoom.cc create mode 100644 krita/ui/kis_label_zoom.h create mode 100644 krita/ui/kis_layerbox.cc create mode 100644 krita/ui/kis_layerbox.h create mode 100644 krita/ui/kis_layerlist.cc create mode 100644 krita/ui/kis_layerlist.h create mode 100644 krita/ui/kis_load_visitor.h create mode 100644 krita/ui/kis_matrix_widget.ui create mode 100644 krita/ui/kis_matrix_widget.ui.h create mode 100644 krita/ui/kis_move_event.h create mode 100644 krita/ui/kis_multi_bool_filter_widget.cc create mode 100644 krita/ui/kis_multi_bool_filter_widget.h create mode 100644 krita/ui/kis_multi_double_filter_widget.cc create mode 100644 krita/ui/kis_multi_double_filter_widget.h create mode 100644 krita/ui/kis_multi_integer_filter_widget.cc create mode 100644 krita/ui/kis_multi_integer_filter_widget.h create mode 100644 krita/ui/kis_opengl_canvas.cc create mode 100644 krita/ui/kis_opengl_canvas.h create mode 100644 krita/ui/kis_opengl_canvas_painter.cc create mode 100644 krita/ui/kis_opengl_canvas_painter.h create mode 100644 krita/ui/kis_opengl_image_context.cc create mode 100644 krita/ui/kis_opengl_image_context.h create mode 100644 krita/ui/kis_paintop_box.cc create mode 100644 krita/ui/kis_paintop_box.h create mode 100644 krita/ui/kis_palette_view.cc create mode 100644 krita/ui/kis_palette_view.h create mode 100644 krita/ui/kis_palette_widget.cc create mode 100644 krita/ui/kis_palette_widget.h create mode 100644 krita/ui/kis_part_layer.cc create mode 100644 krita/ui/kis_part_layer.h create mode 100644 krita/ui/kis_part_layer_handler.cc create mode 100644 krita/ui/kis_part_layer_handler.h create mode 100644 krita/ui/kis_pattern_chooser.cc create mode 100644 krita/ui/kis_pattern_chooser.h create mode 100644 krita/ui/kis_perspective_grid_manager.cpp create mode 100644 krita/ui/kis_perspective_grid_manager.h create mode 100644 krita/ui/kis_populate_visitor.h create mode 100644 krita/ui/kis_previewdialog.cc create mode 100644 krita/ui/kis_previewdialog.h create mode 100644 krita/ui/kis_previewwidget.cc create mode 100644 krita/ui/kis_previewwidget.h create mode 100644 krita/ui/kis_previewwidgetbase.ui create mode 100644 krita/ui/kis_qpaintdevice_canvas.cc create mode 100644 krita/ui/kis_qpaintdevice_canvas.h create mode 100644 krita/ui/kis_qpaintdevice_canvas_painter.cc create mode 100644 krita/ui/kis_qpaintdevice_canvas_painter.h create mode 100644 krita/ui/kis_resource_mediator.cc create mode 100644 krita/ui/kis_resource_mediator.h create mode 100644 krita/ui/kis_resourceserver.cc create mode 100644 krita/ui/kis_resourceserver.h create mode 100644 krita/ui/kis_ruler.cc create mode 100644 krita/ui/kis_ruler.h create mode 100644 krita/ui/kis_save_visitor.h create mode 100644 krita/ui/kis_savexml_visitor.h create mode 100644 krita/ui/kis_selection_manager.cc create mode 100644 krita/ui/kis_selection_manager.h create mode 100644 krita/ui/kis_selection_options.cc create mode 100644 krita/ui/kis_selection_options.h create mode 100644 krita/ui/kis_text_brush.cc create mode 100644 krita/ui/kis_text_brush.h create mode 100644 krita/ui/kis_tool.cc create mode 100644 krita/ui/kis_tool.h create mode 100644 krita/ui/kis_tool_controller.h create mode 100644 krita/ui/kis_tool_dummy.cc create mode 100644 krita/ui/kis_tool_dummy.h create mode 100644 krita/ui/kis_tool_factory.h create mode 100644 krita/ui/kis_tool_freehand.cc create mode 100644 krita/ui/kis_tool_freehand.h create mode 100644 krita/ui/kis_tool_manager.cc create mode 100644 krita/ui/kis_tool_manager.h create mode 100644 krita/ui/kis_tool_non_paint.cc create mode 100644 krita/ui/kis_tool_non_paint.h create mode 100644 krita/ui/kis_tool_paint.cc create mode 100644 krita/ui/kis_tool_paint.h create mode 100644 krita/ui/kis_tool_registry.cc create mode 100644 krita/ui/kis_tool_registry.h create mode 100644 krita/ui/kis_tool_shape.cc create mode 100644 krita/ui/kis_tool_shape.h create mode 100644 krita/ui/kis_tool_types.h create mode 100644 krita/ui/kis_view.cc create mode 100644 krita/ui/kis_view.h create mode 100644 krita/ui/kis_view_iface.cc create mode 100644 krita/ui/kis_view_iface.h create mode 100644 krita/ui/kobirdeyepanel.cpp create mode 100644 krita/ui/kobirdeyepanel.h create mode 100644 krita/ui/layerlist.cpp create mode 100644 krita/ui/layerlist.h create mode 100644 krita/ui/squeezedcombobox.cpp create mode 100644 krita/ui/squeezedcombobox.h create mode 100644 krita/ui/wdgapplyprofile.ui create mode 100644 krita/ui/wdgautobrush.ui create mode 100644 krita/ui/wdgautogradient.ui create mode 100644 krita/ui/wdgbirdeye.ui create mode 100644 krita/ui/wdgcolorsettings.ui create mode 100644 krita/ui/wdgcustombrush.ui create mode 100644 krita/ui/wdgcustompalette.ui create mode 100644 krita/ui/wdgcustompattern.ui create mode 100644 krita/ui/wdgdisplaysettings.ui create mode 100644 krita/ui/wdggeneralsettings.ui create mode 100644 krita/ui/wdggridsettings.ui create mode 100644 krita/ui/wdglayerbox.ui create mode 100644 krita/ui/wdglayerproperties.ui create mode 100644 krita/ui/wdgnewimage.ui create mode 100644 krita/ui/wdgpalettechooser.ui create mode 100644 krita/ui/wdgperformancesettings.ui create mode 100644 krita/ui/wdgpressuresettings.ui create mode 100644 krita/ui/wdgselectionoptions.ui create mode 100644 krita/ui/wdgshapeoptions.ui create mode 100644 krita/ui/wdgtabletdevicesettings.ui create mode 100644 krita/ui/wdgtabletsettings.ui create mode 100644 krita/ui/wdgtextbrush.ui (limited to 'krita') diff --git a/krita/AUTHORS b/krita/AUTHORS new file mode 100644 index 00000000..3ef41cde --- /dev/null +++ b/krita/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/krita/ChangeLog b/krita/ChangeLog new file mode 100644 index 00000000..15793398 --- /dev/null +++ b/krita/ChangeLog @@ -0,0 +1 @@ +We really should use cvs2changelog or something like that... diff --git a/krita/HACKING b/krita/HACKING new file mode 100644 index 00000000..9e89f762 --- /dev/null +++ b/krita/HACKING @@ -0,0 +1,93 @@ +Since 1999, people have been hacking on Krita. 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 + + Krita doesn't use Qt's properties -- yet. If you want to introduce use of + properties, convert any and all classes in Krita 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 + + Krita has started to use designer. All dialogs and all widgets that have a layout + 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 Krita + 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 signals + + Prefix slots with slot and signals with sig: slotUpdateSelection, sigSelectionUpdated. + +Boudewijn Rempt \ No newline at end of file diff --git a/krita/IMAGE_LIBRARIES b/krita/IMAGE_LIBRARIES new file mode 100644 index 00000000..8b4763d2 --- /dev/null +++ b/krita/IMAGE_LIBRARIES @@ -0,0 +1,259 @@ +WARNING: OBSOLETE (Krita'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 Krita, 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 Krita, Vigra look like it's the best bet from a technical +point of view, with Vips a good runner-up. + + +* Krita (http://koffice.kde.org/krita) + +Krita 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 shapes 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. Krita 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 Krita + - 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/krita/Makefile.am b/krita/Makefile.am new file mode 100644 index 00000000..c7c74593 --- /dev/null +++ b/krita/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 = libkritacommon.la +libkritacommon_la_SOURCES = dummy.cc +libkritacommon_la_LDFLAGS = $(all_libraries) -version-info 1:0 -no-undefined +libkritacommon_la_LIBADD = sdk/libkritasdk.la core/libkritaimage.la ui/libkritaui.la kritacolor/libkritacolor.la $(LCMS_LIBS) $(LIB_KOFFICEUI) $(LIB_KOPAINTER) $(LIB_KOPALETTE) $(LIB_XINPUTEXT) + +## The part +kde_module_LTLIBRARIES = libkritapart.la +libkritapart_la_SOURCES = krita_part_init.cc +libkritapart_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +libkritapart_la_LIBADD = libkritacommon.la + +METASOURCES = AUTO + +## The kdeinit loadable module and executable +kdeinit_LTLIBRARIES = krita.la +bin_PROGRAMS = +krita_la_SOURCES = main.cc +krita_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +krita_la_LIBADD = $(LIB_KOFFICECORE) + +xdg_apps_DATA = krita.desktop +kdemimedir = $(kde_mimedir)/application + +rcdir = $(kde_datadir)/krita +rc_DATA = krita.rc krita_readonly.rc + +SUBDIRS = sdk kritacolor core ui . dtd colorspaces plugins data pics +# Needed to compile libkritacommon.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)/krita.pot + rm -f i18ndata + +DOXYGEN_EXCLUDE = CImg.h colorspaces plugins kritacolor/colorspaces core/tiles +include $(top_srcdir)/admin/Doxyfile.am + +kde_services_DATA = kritapart.desktop + diff --git a/krita/README b/krita/README new file mode 100644 index 00000000..ec24af47 --- /dev/null +++ b/krita/README @@ -0,0 +1,13 @@ +Krita + +Krita 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 'krita' is used in a context where this +can be translated with 'perfect' - the perfect age. + +Krita is Swedish for chalk (or pencil?) and rita means "to write". diff --git a/krita/TODO b/krita/TODO new file mode 100644 index 00000000..c301d624 --- /dev/null +++ b/krita/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 krita document embedded in KWord has the wrong scaling and transparency + * A krita 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 Krita images: implement one by + saving a rendered png image into the krita 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 Krita. + * 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 krita + 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 .krita + 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/krita/UIcomments b/krita/UIcomments new file mode 100644 index 00000000..1b924240 --- /dev/null +++ b/krita/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/krita/colorspaces/Makefile.am b/krita/colorspaces/Makefile.am new file mode 100644 index 00000000..8f975e96 --- /dev/null +++ b/krita/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/krita/colorspaces/README b/krita/colorspaces/README new file mode 100644 index 00000000..21e302ff --- /dev/null +++ b/krita/colorspaces/README @@ -0,0 +1,11 @@ +About Modules + +Modules are plug-ins that implement exchangable core functionality +for Krita, such as colour strategies. Modules are loaded at startup +and shared among all Krita 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/krita/colorspaces/cmyk_u16/Makefile.am b/krita/colorspaces/cmyk_u16/Makefile.am new file mode 100644 index 00000000..913ec6ab --- /dev/null +++ b/krita/colorspaces/cmyk_u16/Makefile.am @@ -0,0 +1,30 @@ +kde_services_DATA = krita_cmyk_u16_plugin.desktop + +INCLUDES = -I$(srcdir)/../../sdk \ + -I$(srcdir)/../../kritacolor/color_strategy/ \ + -I$(srcdir)/../../kritacolor/ \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +lib_LTLIBRARIES = libkrita_cmyk_u16.la +libkrita_cmyk_u16_la_SOURCES = kis_cmyk_u16_colorspace.cc +libkrita_cmyk_u16_la_LDFLAGS = $(all_libraries) +libkrita_cmyk_u16_la_LIBADD = ../../kritacolor/libkritacolor.la + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = krita_cmyk_u16_plugin.la + +# Srcs for the plugin +krita_cmyk_u16_plugin_la_SOURCES = cmyk_u16_plugin.cc +noinst_HEADERS = cmyk_u16_plugin.h kis_cmyk_u16_colorspace.h + +krita_cmyk_u16_plugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +krita_cmyk_u16_plugin_la_LIBADD = libkrita_cmyk_u16.la ../../kritacolor/libkritacolor.la + +krita_cmyk_u16_plugin_la_METASOURCES = AUTO +#METASOURCES = AUTO # XXX: which of the two? + + +SUBDIRS = . +#$(TESTSDIR) + diff --git a/krita/colorspaces/cmyk_u16/cmyk_u16_plugin.cc b/krita/colorspaces/cmyk_u16/cmyk_u16_plugin.cc new file mode 100644 index 00000000..a86b09f4 --- /dev/null +++ b/krita/colorspaces/cmyk_u16/cmyk_u16_plugin.cc @@ -0,0 +1,61 @@ +/* +* cmyk_u16_plugin.cc -- Part of Krita +* +* 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( krita_cmyk_u16_plugin, CMYKU16PluginFactory( "krita" ) ) + + +CMYKU16Plugin::CMYKU16Plugin(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(CMYKU16PluginFactory::instance()); + + if ( parent->inherits("KisColorSpaceFactoryRegistry") ) + { + KisColorSpaceFactoryRegistry * f = dynamic_cast( parent ); + + 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/krita/colorspaces/cmyk_u16/cmyk_u16_plugin.h b/krita/colorspaces/cmyk_u16/cmyk_u16_plugin.h new file mode 100644 index 00000000..90dce548 --- /dev/null +++ b/krita/colorspaces/cmyk_u16/cmyk_u16_plugin.h @@ -0,0 +1,37 @@ +/* + * 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 +public: + CMYKU16Plugin(QObject *parent, const char *name, const QStringList &); + virtual ~CMYKU16Plugin(); + +}; + + +#endif // CMYK_U16_PLUGIN_H_ diff --git a/krita/colorspaces/cmyk_u16/kis_cmyk_u16_colorspace.cc b/krita/colorspaces/cmyk_u16/kis_cmyk_u16_colorspace.cc new file mode 100644 index 00000000..92ac3c83 --- /dev/null +++ b/krita/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 Q_INT32 MAX_CHANNEL_CMYK = 4; + const Q_INT32 MAX_CHANNEL_CMYKA = 5; +} + +KisCmykU16ColorSpace::KisCmykU16ColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) : + KisU16BaseColorSpace(KisID("CMYKA16", i18n("CMYK (16-bit integer/channel)")), TYPE_CMYK5_16, icSigCmykData, parent, p) +{ + m_channels.push_back(new KisChannelInfo(i18n("Cyan"), i18n("C"), 0 * sizeof(Q_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(Q_UINT16), Qt::cyan)); + m_channels.push_back(new KisChannelInfo(i18n("Magenta"), i18n("M"), 1 * sizeof(Q_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(Q_UINT16), Qt::magenta)); + m_channels.push_back(new KisChannelInfo(i18n("Yellow"), i18n("Y"), 2 * sizeof(Q_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(Q_UINT16), Qt::yellow)); + m_channels.push_back(new KisChannelInfo(i18n("Black"), i18n("K"), 3 * sizeof(Q_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(Q_UINT16), Qt::black)); + m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), 4 * sizeof(Q_UINT16), KisChannelInfo::ALPHA, KisChannelInfo::UINT16, sizeof(Q_UINT16))); + + m_alphaPos = PIXEL_ALPHA * sizeof(Q_UINT16); + + init(); +} + +KisCmykU16ColorSpace::~KisCmykU16ColorSpace() +{ +} + +void KisCmykU16ColorSpace::mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const +{ + Q_UINT32 totalCyan = 0, totalMagenta = 0, totalYellow = 0, totalBlack = 0, newAlpha = 0; + + while (nColors--) + { + const Pixel *pixel = reinterpret_cast(*colors); + + Q_UINT32 alpha = pixel->alpha; + Q_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(Q_UINT8** colors, Q_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const +{ + Q_INT32 totalCyan = 0, totalMagenta = 0, totalYellow = 0, totalK = 0, totalAlpha = 0; + + while (nColors--) + { + const Pixel * pixel = reinterpret_cast( *colors ); + + Q_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, Q_UINT16_MAX); + p->magenta = CLAMP( ( totalMagenta / factor) + offset, 0, Q_UINT16_MAX); + p->yellow = CLAMP( ( totalYellow / factor) + offset, 0, Q_UINT16_MAX); + p->black = CLAMP( ( totalK / factor) + offset, 0, Q_UINT16_MAX); + } + if (channelFlags & KisChannelInfo::FLAG_ALPHA) { + p->alpha = CLAMP((totalAlpha/ factor) + offset, 0, Q_UINT16_MAX); + } +} + + +void KisCmykU16ColorSpace::invertColor(Q_UINT8 * src, Q_INT32 nPixels) +{ + Q_UINT32 psize = pixelSize(); + + while (nPixels--) + { + Pixel * p = reinterpret_cast< Pixel *>( src ); + p->cyan = Q_UINT16_MAX - p->cyan; + p->magenta = Q_UINT16_MAX - p->magenta; + p->yellow = Q_UINT16_MAX - p->yellow; + p->black = Q_UINT16_MAX - p->black; + src += psize; + } +} + + + +void KisCmykU16ColorSpace::applyAdjustment(const Q_UINT8 *src, Q_UINT8 *dst, KisColorAdjustment *adj, Q_INT32 nPixels) +{ + Q_UINT32 psize = pixelSize(); + + Q_UINT8 * tmp = new Q_UINT8[nPixels * psize]; + Q_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--) + { + Q_UINT16 *pixelAlphaSrc = reinterpret_cast(tmpPtr + m_alphaPos); + Q_UINT16 *pixelAlphaDst = reinterpret_cast(dst + m_alphaPos); + + *pixelAlphaDst= *pixelAlphaSrc; + + tmpPtr += psize; + dst += psize; + } + + delete [] tmp; +} + +QValueVector KisCmykU16ColorSpace::channels() const +{ + return m_channels; +} + +Q_UINT32 KisCmykU16ColorSpace::nChannels() const +{ + return MAX_CHANNEL_CMYKA; +} + +Q_UINT32 KisCmykU16ColorSpace::nColorChannels() const +{ + return MAX_CHANNEL_CMYK; +} + +Q_UINT32 KisCmykU16ColorSpace::pixelSize() const +{ + return MAX_CHANNEL_CMYKA * sizeof(Q_UINT16); +} + +void KisCmykU16ColorSpace::getSingleChannelPixel(Q_UINT8 *dstPixel, const Q_UINT8 *srcPixel, Q_UINT32 channelIndex) +{ + if (channelIndex < (Q_UINT32)MAX_CHANNEL_CMYKA) { + + memset(dstPixel, 0, MAX_CHANNEL_CMYKA * sizeof(Q_UINT16)); + + if (U16_OPACITY_TRANSPARENT != 0) { + dstPixel[PIXEL_ALPHA] = U16_OPACITY_TRANSPARENT; + } + + memcpy(dstPixel + (channelIndex * sizeof(Q_UINT16)), srcPixel + (channelIndex * sizeof(Q_UINT16)), sizeof(Q_UINT16)); + } +} + +void KisCmykU16ColorSpace::compositeOver(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + while (rows > 0) { + + const Q_UINT16 *src = reinterpret_cast(srcRowStart); + Q_UINT16 *dst = reinterpret_cast(dstRowStart); + const Q_UINT8 *mask = maskRowStart; + Q_INT32 columns = numColumns; + + while (columns > 0) { + + Q_UINT16 srcAlpha = src[PIXEL_ALPHA]; + + // apply the alphamask + if (mask != 0) { + Q_UINT8 U8_mask = *mask; + + if (U8_mask != OPACITY_OPAQUE) { + srcAlpha = UINT16_MULT(srcAlpha, UINT8_TO_UINT16(U8_mask)); + } + mask++; + } + + 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(Q_UINT16)); + } else { + Q_UINT16 dstAlpha = dst[PIXEL_ALPHA]; + + Q_UINT16 srcBlend; + + if (dstAlpha == U16_OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + Q_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(Q_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(maskRowStart) { + maskRowStart += maskRowStride; + } + } +} + +#define COMMON_COMPOSITE_OP_PROLOG() \ + while (rows > 0) { \ + \ + const Q_UINT16 *src = reinterpret_cast(srcRowStart); \ + Q_UINT16 *dst = reinterpret_cast(dstRowStart); \ + Q_INT32 columns = numColumns; \ + const Q_UINT8 *mask = maskRowStart; \ + \ + while (columns > 0) { \ + \ + Q_UINT16 srcAlpha = src[PIXEL_ALPHA]; \ + Q_UINT16 dstAlpha = dst[PIXEL_ALPHA]; \ + \ + srcAlpha = QMIN(srcAlpha, dstAlpha); \ + \ + if (mask != 0) { \ + Q_UINT8 U8_mask = *mask; \ + \ + if (U8_mask != OPACITY_OPAQUE) { \ + srcAlpha = UINT16_MULT(srcAlpha, UINT8_TO_UINT16(U8_mask)); \ + } \ + mask++; \ + } \ + \ + if (srcAlpha != U16_OPACITY_TRANSPARENT) { \ + \ + if (opacity != U16_OPACITY_OPAQUE) { \ + srcAlpha = UINT16_MULT(srcAlpha, opacity); \ + } \ + \ + Q_UINT16 srcBlend; \ + \ + if (dstAlpha == U16_OPACITY_OPAQUE) { \ + srcBlend = srcAlpha; \ + } else { \ + Q_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(maskRowStart) { \ + maskRowStart += maskRowStride; \ + } \ + } + +void KisCmykU16ColorSpace::compositeMultiply(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + + for (int channel = 0; channel < MAX_CHANNEL_CMYK; channel++) { + Q_UINT16 srcColor = src[channel]; + Q_UINT16 dstColor = dst[channel]; + + srcColor = UINT16_MULT(srcColor, dstColor); + + dst[channel] = UINT16_BLEND(srcColor, dstColor, srcBlend); + } + + + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisCmykU16ColorSpace::compositeDivide(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_CMYK; channel++) { + + Q_UINT16 srcColor = src[channel]; + Q_UINT16 dstColor = dst[channel]; + + srcColor = QMIN((dstColor * (UINT16_MAX + 1u) + (srcColor / 2u)) / (1u + srcColor), UINT16_MAX); + + Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisCmykU16ColorSpace::compositeScreen(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_CMYK; channel++) { + + Q_UINT16 srcColor = src[channel]; + Q_UINT16 dstColor = dst[channel]; + + srcColor = UINT16_MAX - UINT16_MULT(UINT16_MAX - dstColor, UINT16_MAX - srcColor); + + Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisCmykU16ColorSpace::compositeOverlay(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_CMYK; channel++) { + + Q_UINT16 srcColor = src[channel]; + Q_UINT16 dstColor = dst[channel]; + + srcColor = UINT16_MULT(dstColor, dstColor + 2u * UINT16_MULT(srcColor, UINT16_MAX - dstColor)); + + Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisCmykU16ColorSpace::compositeDodge(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_CMYK; channel++) { + + Q_UINT16 srcColor = src[channel]; + Q_UINT16 dstColor = dst[channel]; + + srcColor = QMIN((dstColor * (UINT16_MAX + 1u)) / (UINT16_MAX + 1u - srcColor), UINT16_MAX); + + Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisCmykU16ColorSpace::compositeBurn(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_CMYK; channel++) { + + Q_UINT16 srcColor = src[channel]; + Q_UINT16 dstColor = dst[channel]; + + srcColor = QMIN(((UINT16_MAX - dstColor) * (UINT16_MAX + 1u)) / (srcColor + 1u), UINT16_MAX); + if (srcColor > UINT16_MAX - srcColor) srcColor = UINT16_MAX; + + Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisCmykU16ColorSpace::compositeDarken(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_CMYK; channel++) { + + Q_UINT16 srcColor = src[channel]; + Q_UINT16 dstColor = dst[channel]; + + srcColor = QMIN(srcColor, dstColor); + + Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisCmykU16ColorSpace::compositeLighten(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_CMYK; channel++) { + + Q_UINT16 srcColor = src[channel]; + Q_UINT16 dstColor = dst[channel]; + + srcColor = QMAX(srcColor, dstColor); + + Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisCmykU16ColorSpace::compositeErase(Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowSize, + const Q_UINT8 *srcAlphaMask, + Q_INT32 maskRowStride, + Q_INT32 rows, + Q_INT32 cols, + Q_UINT16 /*opacity*/) +{ + while (rows-- > 0) + { + const Pixel *s = reinterpret_cast(src); + Pixel *d = reinterpret_cast(dst); + const Q_UINT8 *mask = srcAlphaMask; + + for (Q_INT32 i = cols; i > 0; i--, s++, d++) + { + Q_UINT16 srcAlpha = s->alpha; + + // apply the alphamask + if (mask != 0) { + Q_UINT8 U8_mask = *mask; + + if (U8_mask != OPACITY_OPAQUE) { + srcAlpha = UINT16_BLEND(srcAlpha, U16_OPACITY_OPAQUE, UINT8_TO_UINT16(U8_mask)); + } + mask++; + } + d->alpha = UINT16_MULT(srcAlpha, d->alpha); + } + + dst += dstRowSize; + src += srcRowSize; + if(srcAlphaMask) { + srcAlphaMask += maskRowStride; + } + } +} + + +void KisCmykU16ColorSpace::bitBlt(Q_UINT8 *dst, + Q_INT32 dstRowStride, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 *mask, + Q_INT32 maskRowStride, + Q_UINT8 U8_opacity, + Q_INT32 rows, + Q_INT32 cols, + const KisCompositeOp& op) +{ + Q_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, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DIVIDE: + compositeDivide(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_LIGHTEN: + compositeLighten(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_HUE: + //compositeHue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_SATURATION: + //compositeSaturation(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_VALUE: + //compositeValue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COLOR: + //compositeColor(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_OVERLAY: + compositeOverlay(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ERASE: + compositeErase(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DODGE: + compositeDodge(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_BURN: + compositeBurn(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ALPHA_DARKEN: + abstractCompositeAlphaDarken( + dst, dstRowStride, src, srcRowStride, mask, maskRowStride, + 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/krita/colorspaces/cmyk_u16/kis_cmyk_u16_colorspace.h b/krita/colorspaces/cmyk_u16/kis_cmyk_u16_colorspace.h new file mode 100644 index 00000000..227e18d2 --- /dev/null +++ b/krita/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 { + Q_UINT16 cyan; + Q_UINT16 magenta; + Q_UINT16 yellow; + Q_UINT16 black; + Q_UINT16 alpha; + }; + +public: + KisCmykU16ColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p); + virtual ~KisCmykU16ColorSpace(); + + virtual bool willDegrade(ColorSpaceIndependence independence) + { + if (independence == TO_RGBA8) + return true; + else + return false; + }; + +public: + + virtual QValueVector channels() const; + virtual Q_UINT32 nChannels() const; + virtual Q_UINT32 nColorChannels() const; + virtual Q_UINT32 pixelSize() const; + + virtual void applyAdjustment(const Q_UINT8 *src, Q_UINT8 *dst, KisColorAdjustment *adj, Q_INT32 nPixels); + virtual void mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const; + virtual void invertColor(Q_UINT8 * src, Q_INT32 nPixels); + virtual void convolveColors(Q_UINT8** colors, Q_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const; + virtual void getSingleChannelPixel(Q_UINT8 *dstPixel, const Q_UINT8 *srcPixel, Q_UINT32 channelIndex); + + virtual KisCompositeOpList userVisiblecompositeOps() const; + +protected: + + virtual void bitBlt(Q_UINT8 *dst, + Q_INT32 dstRowStride, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 *srcAlphaMask, + Q_INT32 maskRowStride, + Q_UINT8 opacity, + Q_INT32 rows, + Q_INT32 cols, + const KisCompositeOp& op); + + void compositeOver(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeMultiply(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeDivide(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeScreen(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeOverlay(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeDodge(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeBurn(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeDarken(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeLighten(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeErase(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + +private: + friend class KisCmykU16ColorSpaceTester; + + static const Q_UINT8 PIXEL_CYAN = 0; + static const Q_UINT8 PIXEL_MAGENTA = 1; + static const Q_UINT8 PIXEL_YELLOW = 2; + static const Q_UINT8 PIXEL_BLACK = 3; + static const Q_UINT8 PIXEL_ALPHA = 4; +}; + +class KisCmykU16ColorSpaceFactory : public KisColorSpaceFactory +{ +public: + /** + * Krita 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 Q_UINT32 colorSpaceType() { return TYPE_CMYK5_16; }; + + virtual icColorSpaceSignature colorSpaceSignature() { return icSigCmykData; }; + + virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) { return new KisCmykU16ColorSpace(parent, p); }; + + virtual QString 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/krita/colorspaces/cmyk_u16/krita_cmyk_u16_plugin.desktop b/krita/colorspaces/cmyk_u16/krita_cmyk_u16_plugin.desktop new file mode 100644 index 00000000..ea14371a --- /dev/null +++ b/krita/colorspaces/cmyk_u16/krita_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=Krita/ColorSpace +Type=Service +X-KDE-Library=krita_cmyk_u16_plugin +X-Krita-Version=2 diff --git a/krita/colorspaces/cmyk_u8/Makefile.am b/krita/colorspaces/cmyk_u8/Makefile.am new file mode 100644 index 00000000..2816451f --- /dev/null +++ b/krita/colorspaces/cmyk_u8/Makefile.am @@ -0,0 +1,20 @@ +kde_services_DATA = kritacmykplugin.desktop + +INCLUDES = -I$(srcdir)/../../sdk \ + -I$(srcdir)/../../kritacolor/color_strategy \ + -I$(srcdir)/../../kritacolor \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = kritacmykplugin.la + +kritacmykplugin_la_SOURCES = cmyk_plugin.cc kis_cmyk_colorspace.cc +noinst_HEADERS = cmyk_plugin.h kis_cmyk_colorspace.h + +kritacmykplugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritacmykplugin_la_LIBADD = ../../kritacolor/libkritacolor.la + +kritacmykplugin_la_METASOURCES = AUTO + + +SUBDIRS=templates diff --git a/krita/colorspaces/cmyk_u8/cmyk_plugin.cc b/krita/colorspaces/cmyk_u8/cmyk_plugin.cc new file mode 100644 index 00000000..ccd5a1b4 --- /dev/null +++ b/krita/colorspaces/cmyk_u8/cmyk_plugin.cc @@ -0,0 +1,66 @@ +/* + * cmyk_plugin.cc -- Part of Krita + * + * 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( kritacmykplugin, CMYKPluginFactory( "krita" ) ) + + +CMYKPlugin::CMYKPlugin(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(CMYKPluginFactory::instance()); + if ( parent->inherits("KisColorSpaceFactoryRegistry") ) + { + KisColorSpaceFactoryRegistry * f = dynamic_cast( parent ); + + 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/krita/colorspaces/cmyk_u8/cmyk_plugin.h b/krita/colorspaces/cmyk_u8/cmyk_plugin.h new file mode 100644 index 00000000..c9cee97d --- /dev/null +++ b/krita/colorspaces/cmyk_u8/cmyk_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 CMYK_PLUGIN_H_ +#define CMYK_PLUGIN_H_ + +#include + +/** + * A plugin wrapper around the CMYK colour space strategy. + */ +class CMYKPlugin : public KParts::Plugin +{ + Q_OBJECT +public: + CMYKPlugin(QObject *parent, const char *name, const QStringList &); + virtual ~CMYKPlugin(); + + +}; + +#endif // CMYK_PLUGIN_H_ diff --git a/krita/colorspaces/cmyk_u8/cmykplugin.rc b/krita/colorspaces/cmyk_u8/cmykplugin.rc new file mode 100644 index 00000000..915a1d0a --- /dev/null +++ b/krita/colorspaces/cmyk_u8/cmykplugin.rc @@ -0,0 +1,7 @@ + + +&Image + &Mode + + + diff --git a/krita/colorspaces/cmyk_u8/composite.h b/krita/colorspaces/cmyk_u8/composite.h new file mode 100644 index 00000000..a037a054 --- /dev/null +++ b/krita/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(Q_INT32 stride, + Q_UINT8 *dst, + Q_INT32 dststride, + Q_UINT8 *src, + Q_INT32 srcstride, + Q_INT32 rows, + Q_INT32 cols, + Q_UINT8 opacity = OPACITY_OPAQUE) +{ + compositeCopyChannel(PIXEL_CYAN, stride, dst, dststride, src, srcstride, rows, cols, opacity); +} + + +void compositeCopyMagenta(Q_INT32 stride, + Q_UINT8 *dst, + Q_INT32 dststride, + Q_UINT8 *src, + Q_INT32 srcstride, + Q_INT32 rows, + Q_INT32 cols, + Q_UINT8 opacity = OPACITY_OPAQUE) +{ + compositeCopyChannel(PIXEL_MAGENTA, stride, dst, dststride, src, srcstride, rows, cols, opacity); + +} + + +void compositeCopyYellow(Q_INT32 stride, + Q_UINT8 *dst, + Q_INT32 dststride, + Q_UINT8 *src, + Q_INT32 srcstride, + Q_INT32 rows, + Q_INT32 cols, + Q_UINT8 opacity = OPACITY_OPAQUE) +{ + compositeCopyChannel(PIXEL_YELLOW, stride, dst, dststride, src, srcstride, rows, cols, opacity); + +} + + +void compositeCopyBlack(Q_INT32 stride, + Q_UINT8 *dst, + Q_INT32 dststride, + Q_UINT8 *src, + Q_INT32 srcstride, + Q_INT32 rows, + Q_INT32 cols, + Q_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/krita/colorspaces/cmyk_u8/kis_cmyk_colorspace.cc b/krita/colorspaces/cmyk_u8/kis_cmyk_colorspace.cc new file mode 100644 index 00000000..d40be017 --- /dev/null +++ b/krita/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 Q_INT32 MAX_CHANNEL_CMYK = 4; + const Q_INT32 MAX_CHANNEL_CMYKA = 5; +} + +KisCmykColorSpace::KisCmykColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) : + KisU8BaseColorSpace(KisID("CMYK", i18n("CMYK")), TYPE_CMYK5_8, icSigCmykData, parent, p) +{ + m_channels.push_back(new KisChannelInfo(i18n("Cyan"), i18n("C"), 0, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, Qt::cyan)); + m_channels.push_back(new KisChannelInfo(i18n("Magenta"), i18n("M"), 1, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, Qt::magenta)); + m_channels.push_back(new KisChannelInfo(i18n("Yellow"), i18n("Y"), 2, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, Qt::yellow)); + m_channels.push_back(new KisChannelInfo(i18n("Black"), i18n("K"), 3, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, Qt::black)); + m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), 4, KisChannelInfo::ALPHA, KisChannelInfo::UINT8, 1, Qt::white)); + + m_alphaPos = PIXEL_CMYK_ALPHA; + + init(); +} + +KisCmykColorSpace::~KisCmykColorSpace() +{ +} + +void KisCmykColorSpace::mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const +{ + Q_UINT32 totalCyan = 0, totalMagenta = 0, totalYellow = 0, totalK = 0, totalAlpha = 0; + + while (nColors--) + { + Q_UINT32 alpha = (*colors)[4]; + Q_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 + + Q_UINT32 dstCyan = totalCyan; + if (dstCyan > 255) dstCyan = 255; + dst[0] = dstCyan; + + Q_UINT32 dstMagenta = totalMagenta; + if (dstMagenta > 255) dstMagenta = 255; + dst[1] = dstMagenta; + + Q_UINT32 dstYellow = totalYellow; + if (dstYellow > 255) dstYellow = 255; + dst[2] = dstYellow; + + Q_UINT32 dstK = totalK; + if (dstK > 255) dstK = 255; + dst[3] = dstK; +} + + +void KisCmykColorSpace::convolveColors(Q_UINT8** colors, Q_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const +{ + Q_INT32 totalCyan = 0, totalMagenta = 0, totalYellow = 0, totalK = 0, totalAlpha = 0; + + while (nColors--) + { + Q_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, Q_UINT8_MAX); + dst[PIXEL_MAGENTA] = CLAMP((totalMagenta / factor) + offset, 0, Q_UINT8_MAX); + dst[PIXEL_YELLOW] = CLAMP((totalYellow / factor) + offset, 0, Q_UINT8_MAX); + dst[PIXEL_BLACK] = CLAMP((totalK / factor) + offset, 0, Q_UINT8_MAX); + } + if (channelFlags & KisChannelInfo::FLAG_ALPHA) { + dst[PIXEL_CMYK_ALPHA] = CLAMP((totalAlpha/ factor) + offset, 0, Q_UINT8_MAX); + } +} + + +void KisCmykColorSpace::invertColor(Q_UINT8 * src, Q_INT32 nPixels) +{ + Q_UINT32 psize = pixelSize(); + + while (nPixels--) + { + src[PIXEL_CYAN] = Q_UINT8_MAX - src[PIXEL_CYAN]; + src[PIXEL_MAGENTA] = Q_UINT8_MAX - src[PIXEL_MAGENTA]; + src[PIXEL_YELLOW] = Q_UINT8_MAX - src[PIXEL_YELLOW]; + src[PIXEL_BLACK] = Q_UINT8_MAX - src[PIXEL_BLACK]; + src += psize; + } +} + +void KisCmykColorSpace::applyAdjustment(const Q_UINT8 *src, Q_UINT8 *dst, KisColorAdjustment *adj, Q_INT32 nPixels) +{ + Q_UINT32 psize = pixelSize(); + + Q_UINT8 * tmp = new Q_UINT8[nPixels * psize]; + Q_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; +} + +QValueVector KisCmykColorSpace::channels() const +{ + return m_channels; +} + +Q_UINT32 KisCmykColorSpace::nChannels() const +{ + return cmyk::MAX_CHANNEL_CMYKA; +} + +Q_UINT32 KisCmykColorSpace::nColorChannels() const +{ + return cmyk::MAX_CHANNEL_CMYK; +} + +Q_UINT32 KisCmykColorSpace::pixelSize() const +{ + return cmyk::MAX_CHANNEL_CMYKA; +} + +void KisCmykColorSpace::getSingleChannelPixel(Q_UINT8 *dstPixel, const Q_UINT8 *srcPixel, Q_UINT32 channelIndex) +{ + if (channelIndex < (Q_UINT32)cmyk::MAX_CHANNEL_CMYKA) { + + memset(dstPixel, 0, cmyk::MAX_CHANNEL_CMYKA * sizeof(Q_UINT8)); + + if (OPACITY_TRANSPARENT != 0) { + dstPixel[PIXEL_CMYK_ALPHA] = OPACITY_TRANSPARENT; + } + + memcpy(dstPixel + (channelIndex * sizeof(Q_UINT8)), srcPixel + (channelIndex * sizeof(Q_UINT8)), sizeof(Q_UINT8)); + } +} + +void KisCmykColorSpace::compositeOver(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + while (rows > 0) { + + const Q_UINT8 *src = srcRowStart; + Q_UINT8 *dst = dstRowStart; + const Q_UINT8 *mask = maskRowStart; + Q_INT32 columns = numColumns; + + while (columns > 0) { + + Q_UINT8 srcAlpha = src[PIXEL_CMYK_ALPHA]; + + // apply the alphamask + if (mask != 0) { + Q_UINT8 U8_mask = *mask; + + if (U8_mask != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(srcAlpha, U8_mask); + } + mask++; + } + + 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(Q_UINT8)); + } else { + Q_UINT8 dstAlpha = dst[PIXEL_CMYK_ALPHA]; + + Q_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + Q_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(Q_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(maskRowStart) { + maskRowStart += maskRowStride; + } + } +} + +#define COMMON_COMPOSITE_OP_PROLOG() \ + while (rows > 0) { \ + \ + const Q_UINT8 *src = srcRowStart; \ + Q_UINT8 *dst = dstRowStart; \ + Q_INT32 columns = numColumns; \ + const Q_UINT8 *mask = maskRowStart; \ + \ + while (columns > 0) { \ + \ + Q_UINT8 srcAlpha = src[PIXEL_CMYK_ALPHA]; \ + Q_UINT8 dstAlpha = dst[PIXEL_CMYK_ALPHA]; \ + \ + srcAlpha = QMIN(srcAlpha, dstAlpha); \ + \ + if (mask != 0) { \ + Q_UINT8 U8_mask = *mask; \ + \ + if (U8_mask != OPACITY_OPAQUE) { \ + srcAlpha = UINT8_MULT(srcAlpha, U8_mask); \ +} \ + mask++; \ +} \ + \ + if (srcAlpha != OPACITY_TRANSPARENT) { \ + \ + if (opacity != OPACITY_OPAQUE) { \ + srcAlpha = UINT8_MULT(srcAlpha, opacity); \ +} \ + \ + Q_UINT8 srcBlend; \ + \ + if (dstAlpha == OPACITY_OPAQUE) { \ + srcBlend = srcAlpha; \ +} else { \ + Q_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(maskRowStart) { \ + maskRowStart += maskRowStride; \ +} \ +} + +void KisCmykColorSpace::compositeMultiply(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + + for (int channel = 0; channel < cmyk::MAX_CHANNEL_CMYK; channel++) { + Q_UINT8 srcColor = src[channel]; + Q_UINT8 dstColor = dst[channel]; + + srcColor = UINT8_MULT(srcColor, dstColor); + + dst[channel] = UINT8_BLEND(srcColor, dstColor, srcBlend); + } + + + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisCmykColorSpace::compositeDivide(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < cmyk::MAX_CHANNEL_CMYK; channel++) { + + Q_UINT8 srcColor = src[channel]; + Q_UINT8 dstColor = dst[channel]; + + srcColor = QMIN((dstColor * (UINT8_MAX + 1u) + (srcColor / 2u)) / (1u + srcColor), UINT8_MAX); + + Q_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisCmykColorSpace::compositeScreen(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < cmyk::MAX_CHANNEL_CMYK; channel++) { + + Q_UINT8 srcColor = src[channel]; + Q_UINT8 dstColor = dst[channel]; + + srcColor = UINT8_MAX - UINT8_MULT(UINT8_MAX - dstColor, UINT8_MAX - srcColor); + + Q_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisCmykColorSpace::compositeOverlay(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < cmyk::MAX_CHANNEL_CMYK; channel++) { + + Q_UINT8 srcColor = src[channel]; + Q_UINT8 dstColor = dst[channel]; + + srcColor = UINT8_MULT(dstColor, dstColor + 2u * UINT8_MULT(srcColor, UINT8_MAX - dstColor)); + + Q_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisCmykColorSpace::compositeDodge(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < cmyk::MAX_CHANNEL_CMYK; channel++) { + + Q_UINT8 srcColor = src[channel]; + Q_UINT8 dstColor = dst[channel]; + + srcColor = QMIN((dstColor * (UINT8_MAX + 1u)) / (UINT8_MAX + 1u - srcColor), UINT8_MAX); + + Q_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisCmykColorSpace::compositeBurn(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < cmyk::MAX_CHANNEL_CMYK; channel++) { + + Q_UINT8 srcColor = src[channel]; + Q_UINT8 dstColor = dst[channel]; + + srcColor = QMIN(((UINT8_MAX - dstColor) * (UINT8_MAX + 1u)) / (srcColor + 1u), UINT8_MAX); + if (srcColor > UINT8_MAX - srcColor) srcColor = UINT8_MAX; + + Q_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisCmykColorSpace::compositeDarken(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < cmyk::MAX_CHANNEL_CMYK; channel++) { + + Q_UINT8 srcColor = src[channel]; + Q_UINT8 dstColor = dst[channel]; + + srcColor = QMIN(srcColor, dstColor); + + Q_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisCmykColorSpace::compositeLighten(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < cmyk::MAX_CHANNEL_CMYK; channel++) { + + Q_UINT8 srcColor = src[channel]; + Q_UINT8 dstColor = dst[channel]; + + srcColor = QMAX(srcColor, dstColor); + + Q_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisCmykColorSpace::compositeErase(Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowSize, + const Q_UINT8 *srcAlphaMask, + Q_INT32 maskRowStride, + Q_INT32 rows, + Q_INT32 cols, + Q_UINT8 /*opacity*/) +{ + while (rows-- > 0) + { + const Pixel *s = reinterpret_cast(src); + Pixel *d = reinterpret_cast(dst); + const Q_UINT8 *mask = srcAlphaMask; + + for (Q_INT32 i = cols; i > 0; i--, s++, d++) + { + Q_UINT8 srcAlpha = s->alpha; + + // apply the alphamask + if (mask != 0) { + Q_UINT8 U8_mask = *mask; + + if (U8_mask != OPACITY_OPAQUE) { + srcAlpha = UINT8_BLEND(srcAlpha, OPACITY_OPAQUE, U8_mask); + } + mask++; + } + d->alpha = UINT8_MULT(srcAlpha, d->alpha); + } + + dst += dstRowSize; + src += srcRowSize; + if(srcAlphaMask) { + srcAlphaMask += maskRowStride; + } + } +} + +void KisCmykColorSpace::bitBlt(Q_UINT8 *dst, + Q_INT32 dstRowStride, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 *mask, + Q_INT32 maskRowStride, + Q_UINT8 opacity, + Q_INT32 rows, + Q_INT32 cols, + const KisCompositeOp& op) +{ + + switch (op.op()) { + case COMPOSITE_UNDEF: + // Undefined == no composition + break; + case COMPOSITE_OVER: + compositeOver(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DIVIDE: + compositeDivide(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_LIGHTEN: + compositeLighten(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_HUE: + //compositeHue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_SATURATION: + //compositeSaturation(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_VALUE: + //compositeValue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COLOR: + //compositeColor(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_OVERLAY: + compositeOverlay(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ERASE: + compositeErase(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DODGE: + compositeDodge(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_BURN: + compositeBurn(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ALPHA_DARKEN: + abstractCompositeAlphaDarken( + dst, dstRowStride, src, srcRowStride, mask, maskRowStride, + 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/krita/colorspaces/cmyk_u8/kis_cmyk_colorspace.h b/krita/colorspaces/cmyk_u8/kis_cmyk_colorspace.h new file mode 100644 index 00000000..b918f1aa --- /dev/null +++ b/krita/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 { + Q_UINT16 cyan; + Q_UINT16 magenta; + Q_UINT16 yellow; + Q_UINT16 black; + Q_UINT16 alpha; + }; +public: + KisCmykColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p); + virtual ~KisCmykColorSpace(); + + + virtual bool willDegrade(ColorSpaceIndependence independence) + { + if (independence == TO_RGBA8) + return true; + else + return false; + }; + + + +public: + + virtual void mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const; + virtual void applyAdjustment(const Q_UINT8 *src, Q_UINT8 *dst, KisColorAdjustment *adj, Q_INT32 nPixels); + virtual void invertColor(Q_UINT8 * src, Q_INT32 nPixels); + virtual void convolveColors(Q_UINT8** colors, Q_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const; + // XXX: darken & intensity8? + + virtual QValueVector channels() const; + virtual Q_UINT32 nChannels() const; + virtual Q_UINT32 nColorChannels() const; + virtual Q_UINT32 pixelSize() const; + virtual void getSingleChannelPixel(Q_UINT8 *dstPixel, const Q_UINT8 *srcPixel, Q_UINT32 channelIndex); + + virtual KisCompositeOpList userVisiblecompositeOps() const; + +protected: + + virtual void bitBlt(Q_UINT8 *dst, + Q_INT32 dstRowStride, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 *srcAlphaMask, + Q_INT32 maskRowStride, + Q_UINT8 opacity, + Q_INT32 rows, + Q_INT32 cols, + const KisCompositeOp& op); + + void compositeOver(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeMultiply(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeDivide(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeScreen(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeOverlay(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeDodge(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeBurn(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeDarken(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeLighten(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeErase(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + +private: + + Q_UINT8 * m_qcolordata; + + static const Q_UINT8 PIXEL_CYAN = 0; + static const Q_UINT8 PIXEL_MAGENTA = 1; + static const Q_UINT8 PIXEL_YELLOW = 2; + static const Q_UINT8 PIXEL_BLACK = 3; + static const Q_UINT8 PIXEL_CMYK_ALPHA = 4; +}; + +class KisCmykColorSpaceFactory : public KisColorSpaceFactory +{ +public: + /** + * Krita 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 Q_UINT32 colorSpaceType() { return TYPE_CMYK5_8; }; + + virtual icColorSpaceSignature colorSpaceSignature() { return icSigCmykData; }; + + virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) { return new KisCmykColorSpace(parent, p); }; + + virtual QString 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/krita/colorspaces/cmyk_u8/kritacmykplugin.desktop b/krita/colorspaces/cmyk_u8/kritacmykplugin.desktop new file mode 100644 index 00000000..5ae04a6f --- /dev/null +++ b/krita/colorspaces/cmyk_u8/kritacmykplugin.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=Krita/ColorSpace +Type=Service +X-KDE-Library=kritacmykplugin +X-Krita-Version=2 + diff --git a/krita/colorspaces/cmyk_u8/templates/.directory b/krita/colorspaces/cmyk_u8/templates/.directory new file mode 100644 index 00000000..f69b12ea --- /dev/null +++ b/krita/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/krita/colorspaces/cmyk_u8/templates/Makefile.am b/krita/colorspaces/cmyk_u8/templates/Makefile.am new file mode 100644 index 00000000..7a975df8 --- /dev/null +++ b/krita/colorspaces/cmyk_u8/templates/Makefile.am @@ -0,0 +1,8 @@ +templates_DATA = .directory white_2000x800.desktop +templatesdir = $(kde_datadir)/krita/templates/cmyk + +templatesrc_DATA = white_2000x800.kra +templatesrcdir = $(kde_datadir)/krita/templates/cmyk/.source + +templatesicon_ICON = AUTO +templatesicondir = $(kde_datadir)/krita/icons diff --git a/krita/colorspaces/cmyk_u8/templates/cr48-action-template_cmyk_empty.png b/krita/colorspaces/cmyk_u8/templates/cr48-action-template_cmyk_empty.png new file mode 100644 index 00000000..5c844c2f Binary files /dev/null and b/krita/colorspaces/cmyk_u8/templates/cr48-action-template_cmyk_empty.png differ diff --git a/krita/colorspaces/cmyk_u8/templates/crsc-action-template_cmyk_empty.svgz b/krita/colorspaces/cmyk_u8/templates/crsc-action-template_cmyk_empty.svgz new file mode 100644 index 00000000..a1ad0ae5 Binary files /dev/null and b/krita/colorspaces/cmyk_u8/templates/crsc-action-template_cmyk_empty.svgz differ diff --git a/krita/colorspaces/cmyk_u8/templates/white_2000x800.desktop b/krita/colorspaces/cmyk_u8/templates/white_2000x800.desktop new file mode 100644 index 00000000..b1632e51 --- /dev/null +++ b/krita/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-Krita-Version=2 + diff --git a/krita/colorspaces/cmyk_u8/templates/white_2000x800.kra b/krita/colorspaces/cmyk_u8/templates/white_2000x800.kra new file mode 100644 index 00000000..7fb7a166 Binary files /dev/null and b/krita/colorspaces/cmyk_u8/templates/white_2000x800.kra differ diff --git a/krita/colorspaces/gray_u16/Makefile.am b/krita/colorspaces/gray_u16/Makefile.am new file mode 100644 index 00000000..d9ec51e1 --- /dev/null +++ b/krita/colorspaces/gray_u16/Makefile.am @@ -0,0 +1,29 @@ +# location for the rc file +kde_services_DATA = krita_gray_u16_plugin.desktop + +INCLUDES = -I$(srcdir)/../../sdk \ + -I$(srcdir)/../../kritacolor/color_strategy \ + -I$(srcdir)/../../kritacolor/ \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +lib_LTLIBRARIES = libkrita_gray_u16.la +libkrita_gray_u16_la_SOURCES = kis_gray_u16_colorspace.cc +libkrita_gray_u16_la_LDFLAGS = $(all_libraries) +libkrita_gray_u16_la_LIBADD = ../../kritacolor/libkritacolor.la + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = krita_gray_u16_plugin.la + +# Srcs for the plugin +krita_gray_u16_plugin_la_SOURCES = gray_u16_plugin.cc +noinst_HEADERS = gray_u16_plugin.h kis_gray_u16_colorspace.h + +krita_gray_u16_plugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +krita_gray_u16_plugin_la_LIBADD = libkrita_gray_u16.la ../../kritacolor/libkritacolor.la + +krita_gray_u16_plugin_la_METASOURCES = AUTO + + +SUBDIRS = . + diff --git a/krita/colorspaces/gray_u16/gray_u16_plugin.cc b/krita/colorspaces/gray_u16/gray_u16_plugin.cc new file mode 100644 index 00000000..da32295f --- /dev/null +++ b/krita/colorspaces/gray_u16/gray_u16_plugin.cc @@ -0,0 +1,63 @@ +/* +* gray_u16_plugin.cc -- Part of Krita +* +* 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( krita_gray_u16_plugin, GRAYU16PluginFactory( "krita" ) ) + + +GRAYU16Plugin::GRAYU16Plugin(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(GRAYU16PluginFactory::instance()); + + if ( parent->inherits("KisColorSpaceFactoryRegistry") ) + { + KisColorSpaceFactoryRegistry * f = dynamic_cast( parent ); + + 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/krita/colorspaces/gray_u16/gray_u16_plugin.h b/krita/colorspaces/gray_u16/gray_u16_plugin.h new file mode 100644 index 00000000..89b2e119 --- /dev/null +++ b/krita/colorspaces/gray_u16/gray_u16_plugin.h @@ -0,0 +1,37 @@ +/* + * 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 +public: + GRAYU16Plugin(QObject *parent, const char *name, const QStringList &); + virtual ~GRAYU16Plugin(); + +}; + + +#endif // GRAY_U16_PLUGIN_H_ diff --git a/krita/colorspaces/gray_u16/kis_gray_u16_colorspace.cc b/krita/colorspaces/gray_u16/kis_gray_u16_colorspace.cc new file mode 100644 index 00000000..410d2c9b --- /dev/null +++ b/krita/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 Q_INT32 MAX_CHANNEL_GRAY = 1; + const Q_INT32 MAX_CHANNEL_GRAYA = 2; +} + +KisGrayU16ColorSpace::KisGrayU16ColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) : + KisU16BaseColorSpace(KisID("GRAYA16", i18n("Grayscale (16-bit integer/channel)")), TYPE_GRAYA_16, icSigGrayData, parent, p) +{ + m_channels.push_back(new KisChannelInfo(i18n("Gray"), i18n("G"), PIXEL_GRAY * sizeof(Q_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(Q_UINT16))); + m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), PIXEL_ALPHA * sizeof(Q_UINT16), KisChannelInfo::ALPHA, KisChannelInfo::UINT16, sizeof(Q_UINT16))); + +/* LPGAMMATABLE Gamma = cmsBuildGamma(256, 2.2); + cmsHPROFILE hProfile = cmsCreateGrayProfile(cmsD50_xyY(), Gamma); + cmsFreeGamma(Gamma); +*/ + + m_alphaPos = PIXEL_ALPHA * sizeof(Q_UINT16); + + init(); +} + +KisGrayU16ColorSpace::~KisGrayU16ColorSpace() +{ +} + +void KisGrayU16ColorSpace::mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const +{ + Q_UINT32 totalGray = 0, newAlpha = 0; + + while (nColors--) + { + const Pixel *pixel = reinterpret_cast(*colors); + + Q_UINT32 alpha = pixel->alpha; + Q_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(Q_UINT8** colors, Q_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, + Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const +{ + Q_INT32 totalGray = 0, totalAlpha = 0; + + while (nColors--) + { + const Pixel * pixel = reinterpret_cast( *colors ); + + Q_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, Q_UINT16_MAX); + } + if (channelFlags & KisChannelInfo::FLAG_ALPHA) { + p->alpha = CLAMP((totalAlpha/ factor) + offset, 0, Q_UINT16_MAX); + } +} + + +void KisGrayU16ColorSpace::invertColor(Q_UINT8 * src, Q_INT32 nPixels) +{ + Q_UINT32 psize = pixelSize(); + + while (nPixels--) + { + Pixel * p = reinterpret_cast< Pixel *>( src ); + p->gray = Q_UINT16_MAX - p->gray; + src += psize; + } +} + + + +Q_UINT8 KisGrayU16ColorSpace::intensity8(const Q_UINT8 * src) const +{ + const Pixel * p = reinterpret_cast( src ); + return UINT16_TO_UINT8(p->gray); +} + + +QValueVector KisGrayU16ColorSpace::channels() const +{ + return m_channels; +} + +Q_UINT32 KisGrayU16ColorSpace::nChannels() const +{ + return MAX_CHANNEL_GRAYA; +} + +Q_UINT32 KisGrayU16ColorSpace::nColorChannels() const +{ + return MAX_CHANNEL_GRAY; +} + +Q_UINT32 KisGrayU16ColorSpace::pixelSize() const +{ + return MAX_CHANNEL_GRAYA * sizeof(Q_UINT16); +} + +void KisGrayU16ColorSpace::compositeOver(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + while (rows > 0) { + + const Q_UINT16 *src = reinterpret_cast(srcRowStart); + Q_UINT16 *dst = reinterpret_cast(dstRowStart); + const Q_UINT8 *mask = maskRowStart; + Q_INT32 columns = numColumns; + + while (columns > 0) { + + Q_UINT16 srcAlpha = src[PIXEL_ALPHA]; + + // apply the alphamask + if (mask != 0) { + Q_UINT8 U8_mask = *mask; + + if (U8_mask != OPACITY_OPAQUE) { + srcAlpha = UINT16_MULT(srcAlpha, UINT8_TO_UINT16(U8_mask)); + } + mask++; + } + + 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(Q_UINT16)); + } else { + Q_UINT16 dstAlpha = dst[PIXEL_ALPHA]; + + Q_UINT16 srcBlend; + + if (dstAlpha == U16_OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + Q_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(Q_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(maskRowStart) { + maskRowStart += maskRowStride; + } + } +} + +#define COMMON_COMPOSITE_OP_PROLOG() \ + while (rows > 0) { \ + \ + const Q_UINT16 *src = reinterpret_cast(srcRowStart); \ + Q_UINT16 *dst = reinterpret_cast(dstRowStart); \ + Q_INT32 columns = numColumns; \ + const Q_UINT8 *mask = maskRowStart; \ + \ + while (columns > 0) { \ + \ + Q_UINT16 srcAlpha = src[PIXEL_ALPHA]; \ + Q_UINT16 dstAlpha = dst[PIXEL_ALPHA]; \ + \ + srcAlpha = QMIN(srcAlpha, dstAlpha); \ + \ + if (mask != 0) { \ + Q_UINT8 U8_mask = *mask; \ + \ + if (U8_mask != OPACITY_OPAQUE) { \ + srcAlpha = UINT16_MULT(srcAlpha, UINT8_TO_UINT16(U8_mask)); \ + } \ + mask++; \ + } \ + \ + if (srcAlpha != U16_OPACITY_TRANSPARENT) { \ + \ + if (opacity != U16_OPACITY_OPAQUE) { \ + srcAlpha = UINT16_MULT(srcAlpha, opacity); \ + } \ + \ + Q_UINT16 srcBlend; \ + \ + if (dstAlpha == U16_OPACITY_OPAQUE) { \ + srcBlend = srcAlpha; \ + } else { \ + Q_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(maskRowStart) { \ + maskRowStart += maskRowStride; \ + } \ + } + +void KisGrayU16ColorSpace::compositeMultiply(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + Q_UINT16 srcColor = src[PIXEL_GRAY]; + Q_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(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_GRAY; channel++) { + + Q_UINT16 srcColor = src[channel]; + Q_UINT16 dstColor = dst[channel]; + + srcColor = QMIN((dstColor * (UINT16_MAX + 1u) + (srcColor / 2u)) / (1u + srcColor), UINT16_MAX); + + Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisGrayU16ColorSpace::compositeScreen(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_GRAY; channel++) { + + Q_UINT16 srcColor = src[channel]; + Q_UINT16 dstColor = dst[channel]; + + srcColor = UINT16_MAX - UINT16_MULT(UINT16_MAX - dstColor, UINT16_MAX - srcColor); + + Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisGrayU16ColorSpace::compositeOverlay(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_GRAY; channel++) { + + Q_UINT16 srcColor = src[channel]; + Q_UINT16 dstColor = dst[channel]; + + srcColor = UINT16_MULT(dstColor, dstColor + 2u * UINT16_MULT(srcColor, UINT16_MAX - dstColor)); + + Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisGrayU16ColorSpace::compositeDodge(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_GRAY; channel++) { + + Q_UINT16 srcColor = src[channel]; + Q_UINT16 dstColor = dst[channel]; + + srcColor = QMIN((dstColor * (UINT16_MAX + 1u)) / (UINT16_MAX + 1u - srcColor), UINT16_MAX); + + Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisGrayU16ColorSpace::compositeBurn(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_GRAY; channel++) { + + Q_UINT16 srcColor = src[channel]; + Q_UINT16 dstColor = dst[channel]; + + srcColor = kMin(((UINT16_MAX - dstColor) * (UINT16_MAX + 1u)) / (srcColor + 1u), UINT16_MAX); + srcColor = kClamp(UINT16_MAX - srcColor, 0u, UINT16_MAX); + + Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisGrayU16ColorSpace::compositeDarken(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_GRAY; channel++) { + + Q_UINT16 srcColor = src[channel]; + Q_UINT16 dstColor = dst[channel]; + + srcColor = QMIN(srcColor, dstColor); + + Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisGrayU16ColorSpace::compositeLighten(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_GRAY; channel++) { + + Q_UINT16 srcColor = src[channel]; + Q_UINT16 dstColor = dst[channel]; + + srcColor = QMAX(srcColor, dstColor); + + Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + + +void KisGrayU16ColorSpace::compositeErase(Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowSize, + const Q_UINT8 *srcAlphaMask, + Q_INT32 maskRowStride, + Q_INT32 rows, + Q_INT32 cols, + Q_UINT16 /*opacity*/) +{ + while (rows-- > 0) + { + const Pixel *s = reinterpret_cast(src); + Pixel *d = reinterpret_cast(dst); + const Q_UINT8 *mask = srcAlphaMask; + + for (Q_INT32 i = cols; i > 0; i--, s++, d++) + { + Q_UINT16 srcAlpha = s->alpha; + + // apply the alphamask + if (mask != 0) { + Q_UINT8 U8_mask = *mask; + + if (U8_mask != OPACITY_OPAQUE) { + srcAlpha = UINT16_BLEND(srcAlpha, U16_OPACITY_OPAQUE, UINT8_TO_UINT16(U8_mask)); + } + mask++; + } + d->alpha = UINT16_MULT(srcAlpha, d->alpha); + } + + dst += dstRowSize; + src += srcRowSize; + if(srcAlphaMask) { + srcAlphaMask += maskRowStride; + } + } +} + +void KisGrayU16ColorSpace::bitBlt(Q_UINT8 *dst, + Q_INT32 dstRowStride, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 *mask, + Q_INT32 maskRowStride, + Q_UINT8 U8_opacity, + Q_INT32 rows, + Q_INT32 cols, + const KisCompositeOp& op) +{ + Q_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, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DIVIDE: + compositeDivide(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_LIGHTEN: + compositeLighten(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_HUE: + //compositeHue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_SATURATION: + //compositeSaturation(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_VALUE: + //compositeValue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COLOR: + //compositeColor(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_OVERLAY: + compositeOverlay(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ERASE: + compositeErase(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DODGE: + compositeDodge(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_BURN: + compositeBurn(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ALPHA_DARKEN: + abstractCompositeAlphaDarken( + dst, dstRowStride, src, srcRowStride, mask, maskRowStride, + 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/krita/colorspaces/gray_u16/kis_gray_u16_colorspace.h b/krita/colorspaces/gray_u16/kis_gray_u16_colorspace.h new file mode 100644 index 00000000..2a206564 --- /dev/null +++ b/krita/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 { + Q_UINT16 gray; + Q_UINT16 alpha; + }; + + virtual bool willDegrade(ColorSpaceIndependence independence) + { + if (independence == TO_RGBA8) + return true; + else + return false; + }; + + +public: + KisGrayU16ColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p); + virtual ~KisGrayU16ColorSpace(); + +public: + virtual void mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const; + virtual void invertColor(Q_UINT8 * src, Q_INT32 nPixels); + virtual void convolveColors(Q_UINT8** colors, Q_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const; + virtual Q_UINT8 intensity8(const Q_UINT8 * src) const; + + virtual QValueVector channels() const; + virtual Q_UINT32 nChannels() const; + virtual Q_UINT32 nColorChannels() const; + virtual Q_UINT32 pixelSize() const; + + virtual KisCompositeOpList userVisiblecompositeOps() const; + + +protected: + + virtual void bitBlt(Q_UINT8 *dst, + Q_INT32 dstRowStride, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 *srcAlphaMask, + Q_INT32 maskRowStride, + Q_UINT8 opacity, + Q_INT32 rows, + Q_INT32 cols, + const KisCompositeOp& op); + + void compositeOver(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeMultiply(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeDivide(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeScreen(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeOverlay(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeDodge(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeBurn(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeDarken(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeLighten(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeErase(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + +private: + friend class KisGrayU16ColorSpaceTester; + + static const Q_UINT8 PIXEL_GRAY = 0; + static const Q_UINT8 PIXEL_ALPHA = 1; +}; + +class KisGrayU16ColorSpaceFactory : public KisColorSpaceFactory +{ +public: + /** + * Krita 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 Q_UINT32 colorSpaceType() { return TYPE_GRAY_16; }; + + virtual icColorSpaceSignature colorSpaceSignature() { return icSigGrayData; }; + + virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) { return new KisGrayU16ColorSpace(parent, p); }; + + virtual QString defaultProfile() { return "gray built-in - (lcms internal)"; }; +}; + +#endif // KIS_STRATEGY_COLORSPACE_GRAY_U16_H_ diff --git a/krita/colorspaces/gray_u16/krita_gray_u16_plugin.desktop b/krita/colorspaces/gray_u16/krita_gray_u16_plugin.desktop new file mode 100644 index 00000000..8ba4e38e --- /dev/null +++ b/krita/colorspaces/gray_u16/krita_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=Krita/ColorSpace +Type=Service +X-Krita-Version=2 +X-KDE-Library=krita_gray_u16_plugin diff --git a/krita/colorspaces/gray_u8/Makefile.am b/krita/colorspaces/gray_u8/Makefile.am new file mode 100644 index 00000000..6c84b6b3 --- /dev/null +++ b/krita/colorspaces/gray_u8/Makefile.am @@ -0,0 +1,31 @@ +kde_services_DATA = kritagrayplugin.desktop + +INCLUDES = -I$(srcdir)/../../sdk \ + -I$(srcdir)/../../kritacolor/color_strategy/ \ + -I$(srcdir)/../../kritacolor/ \ + -I$(interfacedir) \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + + +lib_LTLIBRARIES = libkritagrayscale.la +libkritagrayscale_la_SOURCES = kis_gray_colorspace.cc +libkritagrayscale_la_LDFLAGS = $(all_libraries) +libkritagrayscale_la_LIBADD = ../../kritacolor/libkritacolor.la + +kde_module_LTLIBRARIES = kritagrayplugin.la + +kritagrayplugin_la_SOURCES = gray_plugin.cc +noinst_HEADERS = gray_plugin.h kis_gray_colorspace.h + +kritagrayplugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritagrayplugin_la_LIBADD = libkritagrayscale.la ../../kritacolor/libkritacolor.la + +kritagrayplugin_la_METASOURCES = AUTO + +if include_kunittest_tests +TESTSDIR = tests +endif + +SUBDIRS = . templates $(TESTSDIR) + diff --git a/krita/colorspaces/gray_u8/gray_plugin.cc b/krita/colorspaces/gray_u8/gray_plugin.cc new file mode 100644 index 00000000..50fe51cc --- /dev/null +++ b/krita/colorspaces/gray_u8/gray_plugin.cc @@ -0,0 +1,77 @@ +/* + * gray_plugin.cc -- Part of Krita + * + * 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( kritagrayplugin, GrayPluginFactory( "kritacore" ) ) + + +GrayPlugin::GrayPlugin(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(GrayPluginFactory::instance()); + + // This is not a gui plugin; only load it when the doc is created. + if ( parent->inherits("KisColorSpaceFactoryRegistry") ) + { + + KisColorSpaceFactoryRegistry * f = dynamic_cast( parent ); + + // .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/krita/colorspaces/gray_u8/gray_plugin.h b/krita/colorspaces/gray_u8/gray_plugin.h new file mode 100644 index 00000000..9359fa72 --- /dev/null +++ b/krita/colorspaces/gray_u8/gray_plugin.h @@ -0,0 +1,36 @@ +/* + * 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 +public: + GrayPlugin(QObject *parent, const char *name, const QStringList &); + virtual ~GrayPlugin(); + +}; + +#endif // GRAY_PLUGIN_H_ diff --git a/krita/colorspaces/gray_u8/grayplugin.rc b/krita/colorspaces/gray_u8/grayplugin.rc new file mode 100644 index 00000000..e14278e7 --- /dev/null +++ b/krita/colorspaces/gray_u8/grayplugin.rc @@ -0,0 +1,7 @@ + + +&Image + &Mode + + + diff --git a/krita/colorspaces/gray_u8/kis_gray_colorspace.cc b/krita/colorspaces/gray_u8/kis_gray_colorspace.cc new file mode 100644 index 00000000..f5e46416 --- /dev/null +++ b/krita/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) // ((Q_UINT8) (257UL*(value))) + +namespace { + const Q_INT32 MAX_CHANNEL_GRAYSCALE = 1; + const Q_INT32 MAX_CHANNEL_GRAYSCALEA = 2; +} + +KisGrayColorSpace::KisGrayColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) : + KisU8BaseColorSpace(KisID("GRAYA", i18n("Grayscale")), TYPE_GRAYA_8, icSigGrayData, parent, 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(Q_UINT8 *pixel, Q_UINT8 gray, Q_UINT8 alpha) const +{ + pixel[PIXEL_GRAY] = gray; + pixel[PIXEL_GRAY_ALPHA] = alpha; +} + +void KisGrayColorSpace::getPixel(const Q_UINT8 *pixel, Q_UINT8 *gray, Q_UINT8 *alpha) const +{ + *gray = pixel[PIXEL_GRAY]; + *alpha = pixel[PIXEL_GRAY_ALPHA]; +} + +void KisGrayColorSpace::getAlpha(const Q_UINT8 *pixel, Q_UINT8 *alpha) const +{ + *alpha = pixel[PIXEL_GRAY_ALPHA]; +} + +void KisGrayColorSpace::setAlpha(Q_UINT8 *pixels, Q_UINT8 alpha, Q_INT32 nPixels) const +{ + while (nPixels > 0) { + pixels[PIXEL_GRAY_ALPHA] = alpha; + --nPixels; + pixels += MAX_CHANNEL_GRAYSCALEA; + } +} + +void KisGrayColorSpace::mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const +{ + Q_UINT32 totalGray = 0, newAlpha = 0; + + while (nColors--) + { + Q_UINT32 alpha = (*colors)[PIXEL_GRAY_ALPHA]; + Q_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; + Q_UINT32 dstGray = ((totalGray >> 8) + totalGray) >> 8; + Q_ASSERT(dstGray <= 255); + dst[PIXEL_GRAY] = dstGray; +} + +void KisGrayColorSpace::convolveColors(Q_UINT8** colors, Q_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const +{ + Q_INT32 totalGray = 0, totalAlpha = 0; + + while (nColors--) + { + Q_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, Q_UINT8_MAX); + } + if (channelFlags & KisChannelInfo::FLAG_ALPHA) { + dst[PIXEL_GRAY_ALPHA] = CLAMP((totalAlpha/ factor) + offset, 0, Q_UINT8_MAX); + } + +} + + +void KisGrayColorSpace::invertColor(Q_UINT8 * src, Q_INT32 nPixels) +{ + Q_UINT32 psize = pixelSize(); + + while (nPixels--) + { + src[PIXEL_GRAY] = Q_UINT8_MAX - src[PIXEL_GRAY]; + src += psize; + } +} + +void KisGrayColorSpace::darken(const Q_UINT8 * src, Q_UINT8 * dst, Q_INT32 shade, bool compensate, double compensation, Q_INT32 nPixels) const +{ + Q_UINT32 pSize = pixelSize(); + + while (nPixels--) { + if (compensate) { + dst[PIXEL_GRAY] = (Q_INT8) QMIN(255,((src[PIXEL_GRAY] * shade) / (compensation * 255))); + } + else { + dst[PIXEL_GRAY] = (Q_INT8) QMIN(255, (src[PIXEL_GRAY] * shade / 255)); + } + dst += pSize; + src += pSize; + } +} + +Q_UINT8 KisGrayColorSpace::intensity8(const Q_UINT8 * src) const +{ + return src[PIXEL_GRAY]; +} + +QValueVector KisGrayColorSpace::channels() const +{ + return m_channels; +} + +Q_UINT32 KisGrayColorSpace::nChannels() const +{ + return MAX_CHANNEL_GRAYSCALEA; +} + +Q_UINT32 KisGrayColorSpace::nColorChannels() const +{ + return MAX_CHANNEL_GRAYSCALE; +} + +Q_UINT32 KisGrayColorSpace::pixelSize() const +{ + return MAX_CHANNEL_GRAYSCALEA; +} + +void KisGrayColorSpace::bitBlt(Q_UINT8 *dst, + Q_INT32 dstRowStride, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 *mask, + Q_INT32 maskRowStride, + Q_UINT8 opacity, + Q_INT32 rows, + Q_INT32 cols, + const KisCompositeOp& op) +{ + switch (op.op()) { + case COMPOSITE_OVER: + compositeOver(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_MULT: + compositeMultiply(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DIVIDE: + compositeDivide(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DARKEN: + compositeDarken(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_LIGHTEN: + compositeLighten(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_SCREEN: + compositeScreen(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_OVERLAY: + compositeOverlay(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DODGE: + compositeDodge(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_BURN: + compositeBurn(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ERASE: + compositeErase(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY: + compositeCopy(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_CLEAR: { + Q_UINT8 *d; + Q_INT32 linesize; + + linesize = MAX_CHANNEL_GRAYSCALEA*sizeof(Q_UINT8) * cols; + d = dst; + while (rows-- > 0) { + memset(d, 0, linesize); + d += dstRowStride; + } + } + break; + case COMPOSITE_ALPHA_DARKEN: + compositeAlphaDarken(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + while (rows > 0) { + + const Q_UINT8 *src = srcRowStart; + Q_UINT8 *dst = dstRowStart; + Q_INT32 columns = numColumns; + const Q_UINT8 *mask = maskRowStart; + + while (columns > 0) { + + Q_UINT8 srcAlpha = src[PIXEL_GRAY_ALPHA]; + + // apply the alphamask + if(mask != 0) + { + if(*mask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *mask); + mask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(srcAlpha, opacity); + } + + if (srcAlpha == OPACITY_OPAQUE) { + memcpy(dst, src, MAX_CHANNEL_GRAYSCALEA * sizeof(Q_UINT8)); + } else { + Q_UINT8 dstAlpha = dst[PIXEL_GRAY_ALPHA]; + + Q_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + Q_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(Q_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(maskRowStart) + maskRowStart += maskRowStride; + } +} + +void KisGrayColorSpace::compositeMultiply(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + while (rows > 0) { + + const Q_UINT8 *src = srcRowStart; + Q_UINT8 *dst = dstRowStart; + Q_INT32 columns = numColumns; + const Q_UINT8 *mask = maskRowStart; + + while (columns > 0) { + + Q_UINT8 srcAlpha = src[PIXEL_GRAY_ALPHA]; + Q_UINT8 dstAlpha = dst[PIXEL_GRAY_ALPHA]; + + srcAlpha = QMIN(srcAlpha, dstAlpha); + + // apply the alphamask + if(mask != 0) + { + if(*mask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *mask); + mask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_GRAY_ALPHA], opacity); + } + + Q_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + Q_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; + } + } + + Q_UINT8 srcColor = src[PIXEL_GRAY]; + Q_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(maskRowStart) + maskRowStart += maskRowStride; + } +} + +void KisGrayColorSpace::compositeDivide(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + while (rows > 0) { + + const Q_UINT8 *src = srcRowStart; + Q_UINT8 *dst = dstRowStart; + Q_INT32 columns = numColumns; + const Q_UINT8 *mask = maskRowStart; + + while (columns > 0) { + + Q_UINT8 srcAlpha = src[PIXEL_GRAY_ALPHA]; + Q_UINT8 dstAlpha = dst[PIXEL_GRAY_ALPHA]; + + srcAlpha = QMIN(srcAlpha, dstAlpha); + + // apply the alphamask + if(mask != 0) + { + if(*mask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *mask); + mask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_GRAY_ALPHA], opacity); + } + + Q_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + Q_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++) { + + Q_UINT8 srcColor = src[channel]; + Q_UINT8 dstColor = dst[channel]; + + srcColor = QMIN((dstColor * (UINT8_MAX + 1)) / (1 + srcColor), UINT8_MAX); + + Q_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(maskRowStart) + maskRowStart += maskRowStride; + } +} + +void KisGrayColorSpace::compositeScreen(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + while (rows > 0) { + + const Q_UINT8 *src = srcRowStart; + Q_UINT8 *dst = dstRowStart; + Q_INT32 columns = numColumns; + const Q_UINT8 *mask = maskRowStart; + + while (columns > 0) { + + Q_UINT8 srcAlpha = src[PIXEL_GRAY_ALPHA]; + Q_UINT8 dstAlpha = dst[PIXEL_GRAY_ALPHA]; + + srcAlpha = QMIN(srcAlpha, dstAlpha); + + // apply the alphamask + if(mask != 0) + { + if(*mask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *mask); + mask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_GRAY_ALPHA], opacity); + } + + Q_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + Q_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++) { + + Q_UINT8 srcColor = src[channel]; + Q_UINT8 dstColor = dst[channel]; + + srcColor = UINT8_MAX - UINT8_MULT(UINT8_MAX - dstColor, UINT8_MAX - srcColor); + + Q_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(maskRowStart) + maskRowStart += maskRowStride; + } +} + +void KisGrayColorSpace::compositeOverlay(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + while (rows > 0) { + + const Q_UINT8 *src = srcRowStart; + Q_UINT8 *dst = dstRowStart; + Q_INT32 columns = numColumns; + const Q_UINT8 *mask = maskRowStart; + + while (columns > 0) { + + Q_UINT8 srcAlpha = src[PIXEL_GRAY_ALPHA]; + Q_UINT8 dstAlpha = dst[PIXEL_GRAY_ALPHA]; + + srcAlpha = QMIN(srcAlpha, dstAlpha); + + // apply the alphamask + if(mask != 0) + { + if(*mask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *mask); + mask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_GRAY_ALPHA], opacity); + } + + Q_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + Q_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++) { + + Q_UINT8 srcColor = src[channel]; + Q_UINT8 dstColor = dst[channel]; + + srcColor = UINT8_MULT(dstColor, dstColor + UINT8_MULT(2 * srcColor, UINT8_MAX - dstColor)); + + Q_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(maskRowStart) + maskRowStart += maskRowStride; + } +} + +void KisGrayColorSpace::compositeDodge(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + while (rows > 0) { + + const Q_UINT8 *src = srcRowStart; + Q_UINT8 *dst = dstRowStart; + Q_INT32 columns = numColumns; + const Q_UINT8 *mask = maskRowStart; + + while (columns > 0) { + + Q_UINT8 srcAlpha = src[PIXEL_GRAY_ALPHA]; + Q_UINT8 dstAlpha = dst[PIXEL_GRAY_ALPHA]; + + srcAlpha = QMIN(srcAlpha, dstAlpha); + + // apply the alphamask + if(mask != 0) + { + if(*mask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *mask); + mask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_GRAY_ALPHA], opacity); + } + + Q_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + Q_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++) { + + Q_UINT8 srcColor = src[channel]; + Q_UINT8 dstColor = dst[channel]; + + srcColor = QMIN((dstColor * (UINT8_MAX + 1)) / (UINT8_MAX + 1 - srcColor), UINT8_MAX); + + Q_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(maskRowStart) + maskRowStart += maskRowStride; + } +} + +void KisGrayColorSpace::compositeBurn(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + while (rows > 0) { + + const Q_UINT8 *src = srcRowStart; + Q_UINT8 *dst = dstRowStart; + Q_INT32 columns = numColumns; + const Q_UINT8 *mask = maskRowStart; + + while (columns > 0) { + + Q_UINT8 srcAlpha = src[PIXEL_GRAY_ALPHA]; + Q_UINT8 dstAlpha = dst[PIXEL_GRAY_ALPHA]; + + srcAlpha = QMIN(srcAlpha, dstAlpha); + + // apply the alphamask + if(mask != 0) + { + if(*mask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *mask); + mask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_GRAY_ALPHA], opacity); + } + + Q_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + Q_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++) { + + Q_UINT8 srcColor = src[channel]; + Q_UINT8 dstColor = dst[channel]; + + srcColor = kMin(((UINT8_MAX - dstColor) * (UINT8_MAX + 1)) / (srcColor + 1), UINT8_MAX); + srcColor = kClamp(UINT8_MAX - srcColor, 0u, UINT8_MAX); + + Q_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(maskRowStart) + maskRowStart += maskRowStride; + } +} + +void KisGrayColorSpace::compositeDarken(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + while (rows > 0) { + + const Q_UINT8 *src = srcRowStart; + Q_UINT8 *dst = dstRowStart; + Q_INT32 columns = numColumns; + const Q_UINT8 *mask = maskRowStart; + + while (columns > 0) { + + Q_UINT8 srcAlpha = src[PIXEL_GRAY_ALPHA]; + Q_UINT8 dstAlpha = dst[PIXEL_GRAY_ALPHA]; + + srcAlpha = QMIN(srcAlpha, dstAlpha); + + // apply the alphamask + if(mask != 0) + { + if(*mask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *mask); + mask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_GRAY_ALPHA], opacity); + } + + Q_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + Q_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++) { + + Q_UINT8 srcColor = src[channel]; + Q_UINT8 dstColor = dst[channel]; + + srcColor = QMIN(srcColor, dstColor); + + Q_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(maskRowStart) + maskRowStart += maskRowStride; + } +} + +void KisGrayColorSpace::compositeLighten(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + while (rows > 0) { + + const Q_UINT8 *src = srcRowStart; + Q_UINT8 *dst = dstRowStart; + Q_INT32 columns = numColumns; + const Q_UINT8 *mask = maskRowStart; + + while (columns > 0) { + + Q_UINT8 srcAlpha = src[PIXEL_GRAY_ALPHA]; + Q_UINT8 dstAlpha = dst[PIXEL_GRAY_ALPHA]; + + srcAlpha = QMIN(srcAlpha, dstAlpha); + + // apply the alphamask + if(mask != 0) + { + if(*mask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *mask); + mask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_GRAY_ALPHA], opacity); + } + + Q_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + Q_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++) { + + Q_UINT8 srcColor = src[channel]; + Q_UINT8 dstColor = dst[channel]; + + srcColor = QMAX(srcColor, dstColor); + + Q_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(maskRowStart) + maskRowStart += maskRowStride; + } +} + +void KisGrayColorSpace::compositeErase(Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowSize, + const Q_UINT8 *srcAlphaMask, + Q_INT32 maskRowStride, + Q_INT32 rows, + Q_INT32 cols, + Q_UINT8 /*opacity*/) +{ + Q_INT32 i; + Q_UINT8 srcAlpha; + + while (rows-- > 0) + { + const Q_UINT8 *s = src; + Q_UINT8 *d = dst; + const Q_UINT8 *mask = srcAlphaMask; + + for (i = cols; i > 0; i--, s+=MAX_CHANNEL_GRAYSCALEA, d+=MAX_CHANNEL_GRAYSCALEA) + { + srcAlpha = s[PIXEL_GRAY_ALPHA]; + // apply the alphamask + if(mask != 0) + { + if(*mask != OPACITY_OPAQUE) + srcAlpha = UINT8_BLEND(srcAlpha, OPACITY_OPAQUE, *mask); + mask++; + } + d[PIXEL_GRAY_ALPHA] = UINT8_MULT(srcAlpha, d[PIXEL_GRAY_ALPHA]); + } + + dst += dstRowSize; + if(srcAlphaMask) + srcAlphaMask += maskRowStride; + src += srcRowSize; + } +} + +void KisGrayColorSpace::compositeAlphaDarken(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, + const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, + const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, + Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + while (rows > 0) { + + const Q_UINT8 *src = srcRowStart; + Q_UINT8 *dst = dstRowStart; + const Q_UINT8 *mask = maskRowStart; + Q_INT32 columns = numColumns; + + while (columns > 0) { + + Q_UINT8 srcAlpha = src[PIXEL_GRAY_ALPHA]; + Q_UINT8 dstAlpha = dst[PIXEL_GRAY_ALPHA]; + + // apply the alphamask + if(mask != 0) + { + if(*mask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *mask); + mask++; + } + + 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(Q_UINT8)); + } + + columns--; + src += MAX_CHANNEL_GRAYSCALEA; + dst += MAX_CHANNEL_GRAYSCALEA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(maskRowStart) + maskRowStart += maskRowStride; + } +} diff --git a/krita/colorspaces/gray_u8/kis_gray_colorspace.h b/krita/colorspaces/gray_u8/kis_gray_colorspace.h new file mode 100644 index 00000000..d6784017 --- /dev/null +++ b/krita/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 * parent, KisProfile *p); + virtual ~KisGrayColorSpace(); + + virtual bool willDegrade(ColorSpaceIndependence /*independence*/) + { + return false; + }; + +public: + + void setPixel(Q_UINT8 *pixel, Q_UINT8 gray, Q_UINT8 alpha) const; + void getPixel(const Q_UINT8 *pixel, Q_UINT8 *gray, Q_UINT8 *alpha) const; + + virtual void getAlpha(const Q_UINT8 *pixel, Q_UINT8 *alpha) const; + virtual void setAlpha(Q_UINT8 * pixels, Q_UINT8 alpha, Q_INT32 nPixels) const; + + virtual void mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const; + virtual void convolveColors(Q_UINT8** colors, Q_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const; + virtual void invertColor(Q_UINT8 * src, Q_INT32 nPixels); + virtual void darken(const Q_UINT8 * src, Q_UINT8 * dst, Q_INT32 shade, bool compensate, double compensation, Q_INT32 nPixels) const; + virtual Q_UINT8 intensity8(const Q_UINT8 * src) const; + + virtual QValueVector channels() const; + virtual Q_UINT32 nChannels() const; + virtual Q_UINT32 nColorChannels() const; + virtual Q_UINT32 pixelSize() const; + + virtual void bitBlt(Q_UINT8 *dst, + Q_INT32 dststride, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 *srcAlphaMask, + Q_INT32 maskRowStride, + Q_UINT8 opacity, + Q_INT32 rows, + Q_INT32 cols, + const KisCompositeOp& op); + + KisCompositeOpList userVisiblecompositeOps() const; + +protected: + void compositeOver(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeMultiply(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeDivide(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeScreen(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeOverlay(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeDodge(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeBurn(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeDarken(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeLighten(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeErase(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeAlphaDarken(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + + +private: + friend class KisGrayColorSpaceTester; + + static const Q_UINT8 PIXEL_GRAY = 0; + static const Q_UINT8 PIXEL_GRAY_ALPHA = 1; +}; + +class KisGrayColorSpaceFactory : public KisColorSpaceFactory +{ +public: + /** + * Krita 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 Q_UINT32 colorSpaceType() { return TYPE_GRAYA_8; }; + + virtual icColorSpaceSignature colorSpaceSignature() { return icSigGrayData; }; + + virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) { return new KisGrayColorSpace(parent, p); }; + + virtual QString defaultProfile() { return "gray built-in - (lcms internal)"; }; +}; + +#endif // KIS_STRATEGY_COLORSPACE_GRAYSCALE_H_ diff --git a/krita/colorspaces/gray_u8/kritagrayplugin.desktop b/krita/colorspaces/gray_u8/kritagrayplugin.desktop new file mode 100644 index 00000000..cd810f81 --- /dev/null +++ b/krita/colorspaces/gray_u8/kritagrayplugin.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=Krita/ColorSpace +Type=Service +X-KDE-Library=kritagrayplugin +X-Krita-Version=2 diff --git a/krita/colorspaces/gray_u8/templates/.directory b/krita/colorspaces/gray_u8/templates/.directory new file mode 100644 index 00000000..e408f23f --- /dev/null +++ b/krita/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/krita/colorspaces/gray_u8/templates/Makefile.am b/krita/colorspaces/gray_u8/templates/Makefile.am new file mode 100644 index 00000000..2b185223 --- /dev/null +++ b/krita/colorspaces/gray_u8/templates/Makefile.am @@ -0,0 +1,8 @@ +templates_DATA = .directory white_640x480.desktop +templatesdir = $(kde_datadir)/krita/templates/gray + +templatesrc_DATA =white_640x480.kra +templatesrcdir = $(kde_datadir)/krita/templates/gray/.source + +templatesicon_ICON = AUTO +templatesicondir = $(kde_datadir)/krita/icons diff --git a/krita/colorspaces/gray_u8/templates/cr48-action-template_gray_empty.png b/krita/colorspaces/gray_u8/templates/cr48-action-template_gray_empty.png new file mode 100644 index 00000000..3ea63818 Binary files /dev/null and b/krita/colorspaces/gray_u8/templates/cr48-action-template_gray_empty.png differ diff --git a/krita/colorspaces/gray_u8/templates/crsc-action-template_gray_empty.svgz b/krita/colorspaces/gray_u8/templates/crsc-action-template_gray_empty.svgz new file mode 100644 index 00000000..93af227f Binary files /dev/null and b/krita/colorspaces/gray_u8/templates/crsc-action-template_gray_empty.svgz differ diff --git a/krita/colorspaces/gray_u8/templates/white_640x480.desktop b/krita/colorspaces/gray_u8/templates/white_640x480.desktop new file mode 100644 index 00000000..cea93b17 --- /dev/null +++ b/krita/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-Krita-Version=2 diff --git a/krita/colorspaces/gray_u8/templates/white_640x480.kra b/krita/colorspaces/gray_u8/templates/white_640x480.kra new file mode 100644 index 00000000..f1865a64 Binary files /dev/null and b/krita/colorspaces/gray_u8/templates/white_640x480.kra differ diff --git a/krita/colorspaces/gray_u8/tests/Makefile.am b/krita/colorspaces/gray_u8/tests/Makefile.am new file mode 100644 index 00000000..f5f14f7c --- /dev/null +++ b/krita/colorspaces/gray_u8/tests/Makefile.am @@ -0,0 +1,17 @@ +AM_CPPFLAGS = -I$(srcdir)/.. \ + -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../kritacolor/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 ../libkritagrayscale.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/krita/colorspaces/gray_u8/tests/kis_strategy_colorspace_grayscale_tester.cpp b/krita/colorspaces/gray_u8/tests/kis_strategy_colorspace_grayscale_tester.cpp new file mode 100644 index 00000000..3c91d6d1 --- /dev/null +++ b/krita/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); + + + Q_UINT8 pixel[MAX_CHANNEL_GRAYSCALEA]; + + pixel[KisGrayColorSpace::PIXEL_GRAY] = 255; + pixel[KisGrayColorSpace::PIXEL_GRAY_ALPHA] = 128; + + QString valueText = cs->channelValueText(pixel, GRAY_CHANNEL); + CHECK(valueText, QString("255")); + + valueText = cs->channelValueText(pixel, ALPHA_CHANNEL); + CHECK(valueText, QString("128")); + + valueText = cs->normalisedChannelValueText(pixel, GRAY_CHANNEL); + CHECK(valueText, QString().setNum(1.0)); + + valueText = cs->normalisedChannelValueText(pixel, ALPHA_CHANNEL); + CHECK(valueText, QString().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); + + Q_UINT8 gray; + Q_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); + + Q_UINT8 pixel1[MAX_CHANNEL_GRAYSCALEA]; + Q_UINT8 pixel2[MAX_CHANNEL_GRAYSCALEA]; + Q_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 Q_UINT8 *pixelPtrs[2]; + Q_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/krita/colorspaces/gray_u8/tests/kis_strategy_colorspace_grayscale_tester.h b/krita/colorspaces/gray_u8/tests/kis_strategy_colorspace_grayscale_tester.h new file mode 100644 index 00000000..9b5f8d5e --- /dev/null +++ b/krita/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/krita/colorspaces/lms_f32/Makefile.am b/krita/colorspaces/lms_f32/Makefile.am new file mode 100644 index 00000000..f34e9a20 --- /dev/null +++ b/krita/colorspaces/lms_f32/Makefile.am @@ -0,0 +1,28 @@ +# Install the desktop file needed to detect the plugin +kde_services_DATA = krita_lms_f32_plugin.desktop + +INCLUDES = \ + -I$(srcdir)/../../sdk \ + -I$(srcdir)/../../kritacolor/color_strategy/ \ + -I$(srcdir)/../../kritacolor/ \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + + +lib_LTLIBRARIES = libkrita_lms_f32.la +libkrita_lms_f32_la_SOURCES = kis_lms_f32_colorspace.cc +libkrita_lms_f32_la_LDFLAGS = $(all_libraries) +libkrita_lms_f32_la_LIBADD = ../../kritacolor/libkritacolor.la + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = krita_lms_f32_plugin.la + +# Srcs for the plugin +krita_lms_f32_plugin_la_SOURCES = lms_f32_plugin.cc +noinst_HEADERS = lms_f32_plugin.h kis_lms_f32_colorspace.h + +krita_lms_f32_plugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +krita_lms_f32_plugin_la_LIBADD = libkrita_lms_f32.la ../../kritacolor/libkritacolor.la + +krita_lms_f32_plugin_la_METASOURCES = AUTO + diff --git a/krita/colorspaces/lms_f32/kis_lms_f32_colorspace.cc b/krita/colorspaces/lms_f32/kis_lms_f32_colorspace.cc new file mode 100644 index 00000000..0c8b91bf --- /dev/null +++ b/krita/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 Q_INT32 MAX_CHANNEL_LMS = 3; + const Q_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 * parent, KisProfile */*p*/) : + KisF32BaseColorSpace(KisID("LMSAF32", i18n("LMS (32-bit float/channel)")), F32_LCMS_TYPE, icSig3colorData, parent, 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(Q_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 Q_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::fromQColor(const QColor& c, Q_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::fromQColor(const QColor& c, Q_UINT8 opacity, Q_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::toQColor(const Q_UINT8 *srcU8, QColor *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::toQColor(const Q_UINT8 *srcU8, QColor *c, Q_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); +} + +Q_UINT8 KisLmsF32ColorSpace::difference(const Q_UINT8 *src1U8, const Q_UINT8 *src2U8) +{ + const Pixel *src1 = reinterpret_cast(src1U8); + const Pixel *src2 = reinterpret_cast(src2U8); + + return FLOAT_TO_UINT8(QMAX(QABS(src2->longWave - src1->longWave), + QMAX(QABS(src2->middleWave - src1->middleWave), + QABS(src2->shortWave - src1->shortWave)))); +} + +void KisLmsF32ColorSpace::mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_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; +} + +QValueVector KisLmsF32ColorSpace::channels() const +{ + return m_channels; +} + +Q_UINT32 KisLmsF32ColorSpace::nChannels() const +{ + return MAX_CHANNEL_LMSA; +} + +Q_UINT32 KisLmsF32ColorSpace::nColorChannels() const +{ + return MAX_CHANNEL_LMS; +} + +Q_UINT32 KisLmsF32ColorSpace::pixelSize() const +{ + return MAX_CHANNEL_LMSA * sizeof(float); +} + +QImage KisLmsF32ColorSpace::convertToQImage(const Q_UINT8 *dataU8, Q_INT32 width, Q_INT32 height, + KisProfile * /*dstProfile*/, + Q_INT32 /*renderingIntent*/, float /*exposure*/) + +{ + const float *data = reinterpret_cast(dataU8); + + QImage img = QImage(width, height, 32, 0, QImage::LittleEndian); + img.setAlphaBuffer(true); + + Q_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(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, float opacity) +{ + while (rows > 0) { + + const float *src = reinterpret_cast(srcRowStart); + float *dst = reinterpret_cast(dstRowStart); + const Q_UINT8 *mask = maskRowStart; + Q_INT32 columns = numColumns; + + while (columns > 0) { + + float srcAlpha = src[PIXEL_ALPHA]; + + // apply the alphamask + if (mask != 0) { + Q_UINT8 U8_mask = *mask; + + if (U8_mask != OPACITY_OPAQUE) { + srcAlpha *= UINT8_TO_FLOAT(U8_mask); + } + mask++; + } + + 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(maskRowStart) { + maskRowStart += maskRowStride; + } + } +} + +void KisLmsF32ColorSpace::compositeErase(Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowSize, + const Q_UINT8 *srcAlphaMask, + Q_INT32 maskRowStride, + Q_INT32 rows, + Q_INT32 cols, + float /*opacity*/) +{ + while (rows-- > 0) + { + const Pixel *s = reinterpret_cast(src); + Pixel *d = reinterpret_cast(dst); + const Q_UINT8 *mask = srcAlphaMask; + + for (Q_INT32 i = cols; i > 0; i--, s++, d++) + { + float srcAlpha = s->alpha; + + // apply the alphamask + if (mask != 0) { + Q_UINT8 U8_mask = *mask; + + if (U8_mask != OPACITY_OPAQUE) { + srcAlpha = FLOAT_BLEND(srcAlpha, F32_OPACITY_OPAQUE, UINT8_TO_FLOAT(U8_mask)); + } + mask++; + } + d->alpha = srcAlpha * d->alpha; + } + + dst += dstRowSize; + src += srcRowSize; + if(srcAlphaMask) { + srcAlphaMask += maskRowStride; + } + } +} + +void KisLmsF32ColorSpace::compositeCopy(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, + const Q_UINT8 */*maskRowStart*/, Q_INT32 /*maskRowStride*/, Q_INT32 rows, Q_INT32 numColumns, float /*opacity*/) +{ + while (rows > 0) { + memcpy(dstRowStart, srcRowStart, numColumns * sizeof(Pixel)); + --rows; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + } +} + +void KisLmsF32ColorSpace::bitBlt(Q_UINT8 *dst, + Q_INT32 dstRowStride, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 *mask, + Q_INT32 maskRowStride, + Q_UINT8 U8_opacity, + Q_INT32 rows, + Q_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, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY: + compositeCopy(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ERASE: + compositeErase(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + default: + break; + } +} + +KisCompositeOpList KisLmsF32ColorSpace::userVisiblecompositeOps() const +{ + KisCompositeOpList list; + + list.append(KisCompositeOp(COMPOSITE_OVER)); + return list; +} + diff --git a/krita/colorspaces/lms_f32/kis_lms_f32_colorspace.h b/krita/colorspaces/lms_f32/kis_lms_f32_colorspace.h new file mode 100644 index 00000000..8d5d27d9 --- /dev/null +++ b/krita/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 * parent, KisProfile *p); + virtual ~KisLmsF32ColorSpace(); + + virtual bool willDegrade(ColorSpaceIndependence independence) + { + if (independence == TO_RGBA8 || independence == TO_LAB16) + return true; + else + return false; + }; + + +public: + void setPixel(Q_UINT8 *pixel, float longWave, float middleWave, float shortWave, float alpha) const; + void getPixel(const Q_UINT8 *pixel, float *longWave, float *middleWave, float *shortWave, float *alpha) const; + + virtual void fromQColor(const QColor& c, Q_UINT8 *dst, KisProfile * profile = 0); + virtual void fromQColor(const QColor& c, Q_UINT8 opacity, Q_UINT8 *dst, KisProfile * profile = 0); + + virtual void toQColor(const Q_UINT8 *src, QColor *c, KisProfile * profile = 0); + virtual void toQColor(const Q_UINT8 *src, QColor *c, Q_UINT8 *opacity, KisProfile * profile = 0); + + virtual Q_UINT8 difference(const Q_UINT8 *src1, const Q_UINT8 *src2); + virtual void mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const; + + virtual QValueVector channels() const; + virtual Q_UINT32 nChannels() const; + virtual Q_UINT32 nColorChannels() const; + virtual Q_UINT32 pixelSize() const; + + virtual bool hasHighDynamicRange() const { return false; } + + virtual QImage convertToQImage(const Q_UINT8 *data, Q_INT32 width, Q_INT32 height, + KisProfile * dstProfile, + Q_INT32 renderingIntent, + float exposure = 0.0f); + + virtual KisCompositeOpList userVisiblecompositeOps() const; + + +protected: + + virtual void bitBlt(Q_UINT8 *dst, + Q_INT32 dstRowStride, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 *srcAlphaMask, + Q_INT32 maskRowStride, + Q_UINT8 opacity, + Q_INT32 rows, + Q_INT32 cols, + const KisCompositeOp& op); + + void compositeOver(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity); + void compositeErase(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity); + void compositeCopy(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity); + +private: + inline Q_UINT8 computeRed(float l, float m, float s) const + { + return FLOAT_TO_UINT8(4.4679*l - 3.58738*m + 0.1193*s); + } + inline Q_UINT8 computeGreen(float l, float m, float s) const + { + return FLOAT_TO_UINT8(-1.2186*l + 2.3809*m - 0.1624*s); + } + inline Q_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(Q_UINT8 r, Q_UINT8 g, Q_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(Q_UINT8 r, Q_UINT8 g, Q_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(Q_UINT8 r, Q_UINT8 g, Q_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 Q_UINT8 PIXEL_LONGWAVE = 0; + static const Q_UINT8 PIXEL_MIDDLEWAVE = 1; + static const Q_UINT8 PIXEL_SHORTWAVE = 2; + static const Q_UINT8 PIXEL_ALPHA = 3; + + struct Pixel { + float longWave; + float middleWave; + float shortWave; + float alpha; + }; +}; + +class KisLmsF32ColorSpaceFactory : public KisColorSpaceFactory +{ +public: + /** + * Krita 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 Q_UINT32 colorSpaceType() { return 0; }; // FIXME: lcms do not support LMS cone space + + virtual icColorSpaceSignature colorSpaceSignature() { return icMaxEnumData; }; + + virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) { return new KisLmsF32ColorSpace(parent, p); }; + + virtual QString defaultProfile() { return "sRGB built-in - (lcms internal)"; }; +}; + +#endif // KIS_STRATEGY_COLORSPACE_LMS_F32_H_ + diff --git a/krita/colorspaces/lms_f32/krita_lms_f32_plugin.desktop b/krita/colorspaces/lms_f32/krita_lms_f32_plugin.desktop new file mode 100644 index 00000000..89951209 --- /dev/null +++ b/krita/colorspaces/lms_f32/krita_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=Krita/ColorSpace +Type=Service +X-KDE-Library=krita_lms_f32_plugin +X-Krita-Version=2 diff --git a/krita/colorspaces/lms_f32/lms_f32_plugin.cc b/krita/colorspaces/lms_f32/lms_f32_plugin.cc new file mode 100644 index 00000000..67df5e4f --- /dev/null +++ b/krita/colorspaces/lms_f32/lms_f32_plugin.cc @@ -0,0 +1,64 @@ +/* +* lms_f32_plugin.cc -- Part of Krita +* +* 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( krita_lms_f32_plugin, LMSF32PluginFactory( "krita" ) ) + + +LMSF32Plugin::LMSF32Plugin(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(LMSF32PluginFactory::instance()); + + if ( parent->inherits("KisColorSpaceFactoryRegistry") ) + { + KisColorSpaceFactoryRegistry * f = dynamic_cast(parent); + + 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/krita/colorspaces/lms_f32/lms_f32_plugin.h b/krita/colorspaces/lms_f32/lms_f32_plugin.h new file mode 100644 index 00000000..b8d02b18 --- /dev/null +++ b/krita/colorspaces/lms_f32/lms_f32_plugin.h @@ -0,0 +1,39 @@ +/* + * 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 +public: + LMSF32Plugin(QObject *parent, const char *name, const QStringList &); + virtual ~LMSF32Plugin(); + +}; + + +#endif // LMS_F32_PLUGIN_H_ diff --git a/krita/colorspaces/lms_f32/lms_f32_plugin.rc b/krita/colorspaces/lms_f32/lms_f32_plugin.rc new file mode 100644 index 00000000..ac6ec45f --- /dev/null +++ b/krita/colorspaces/lms_f32/lms_f32_plugin.rc @@ -0,0 +1,9 @@ + + +&Image + &Mode + + + + + diff --git a/krita/colorspaces/rgb_f16half/Makefile.am b/krita/colorspaces/rgb_f16half/Makefile.am new file mode 100644 index 00000000..d49bd2ef --- /dev/null +++ b/krita/colorspaces/rgb_f16half/Makefile.am @@ -0,0 +1,35 @@ +# Install the desktop file needed to detect the plugin +kde_services_DATA = krita_rgb_f16half_plugin.desktop + +INCLUDES = \ + -I$(srcdir)/../../sdk \ + -I$(srcdir)/../../kritacolor/color_strategy/ \ + -I$(srcdir)/../../kritacolor/ \ + $(OPENEXR_CFLAGS) \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + + +lib_LTLIBRARIES = libkrita_rgb_f16half.la +libkrita_rgb_f16half_la_SOURCES = kis_rgb_f16half_colorspace.cc +libkrita_rgb_f16half_la_LDFLAGS = $(all_libraries) +libkrita_rgb_f16half_la_LIBADD = ../../kritacolor/libkritacolor.la + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = krita_rgb_f16half_plugin.la + +# Srcs for the plugin +krita_rgb_f16half_plugin_la_SOURCES = rgb_f16half_plugin.cc +noinst_HEADERS = rgb_f16half_plugin.h kis_rgb_f16half_colorspace.h + +krita_rgb_f16half_plugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +krita_rgb_f16half_plugin_la_LIBADD = libkrita_rgb_f16half.la ../../kritacolor/libkritacolor.la + +krita_rgb_f16half_plugin_la_METASOURCES = AUTO + +if include_kunittest_tests +TESTSDIR = tests +endif + +SUBDIRS = . $(TESTSDIR) + diff --git a/krita/colorspaces/rgb_f16half/kis_rgb_f16half_colorspace.cc b/krita/colorspaces/rgb_f16half/kis_rgb_f16half_colorspace.cc new file mode 100644 index 00000000..a1826b97 --- /dev/null +++ b/krita/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 Q_INT32 MAX_CHANNEL_RGB = 3; + const Q_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 * parent, KisProfile *p) : + KisF16HalfBaseColorSpace(KisID("RGBAF16HALF", i18n("RGB (16-bit float/channel)")), RGBAF16HALF_LCMS_TYPE, icSigRgbData, parent, 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(Q_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 Q_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::fromQColor(const QColor& c, Q_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::fromQColor(const QColor& c, Q_UINT8 opacity, Q_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::toQColor(const Q_UINT8 *srcU8, QColor *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::toQColor(const Q_UINT8 *srcU8, QColor *c, Q_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); +} + +Q_UINT8 KisRgbF16HalfColorSpace::difference(const Q_UINT8 *src1U8, const Q_UINT8 *src2U8) +{ + const Pixel *src1 = reinterpret_cast(src1U8); + const Pixel *src2 = reinterpret_cast(src2U8); + + return HALF_TO_UINT8(QMAX(QABS(src2->red - src1->red), + QMAX(QABS(src2->green - src1->green), + QABS(src2->blue - src1->blue)))); +} + +void KisRgbF16HalfColorSpace::mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_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(Q_UINT8** colors, Q_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_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(Q_UINT8 * src, Q_INT32 nPixels) +{ + Q_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; + } + +} + + +Q_UINT8 KisRgbF16HalfColorSpace::intensity8(const Q_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); +} + + +QValueVector KisRgbF16HalfColorSpace::channels() const +{ + return m_channels; +} + +Q_UINT32 KisRgbF16HalfColorSpace::nChannels() const +{ + return MAX_CHANNEL_RGBA; +} + +Q_UINT32 KisRgbF16HalfColorSpace::nColorChannels() const +{ + return MAX_CHANNEL_RGB; +} + +Q_UINT32 KisRgbF16HalfColorSpace::pixelSize() const +{ + return MAX_CHANNEL_RGBA * sizeof(half); +} + +Q_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); +} + +QImage KisRgbF16HalfColorSpace::convertToQImage(const Q_UINT8 *dataU8, Q_INT32 width, Q_INT32 height, + KisProfile * /*dstProfile*/, + Q_INT32 /*renderingIntent*/, float exposure) + +{ + const half *data = reinterpret_cast(dataU8); + + QImage img = QImage(width, height, 32, 0, QImage::LittleEndian); + img.setAlphaBuffer(true); + + Q_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(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, half opacity) +{ + while (rows > 0) { + + const half *src = reinterpret_cast(srcRowStart); + half *dst = reinterpret_cast(dstRowStart); + const Q_UINT8 *mask = maskRowStart; + Q_INT32 columns = numColumns; + + while (columns > 0) { + + half srcAlpha = src[PIXEL_ALPHA]; + + // apply the alphamask + if (mask != 0) { + Q_UINT8 U8_mask = *mask; + + if (U8_mask != OPACITY_OPAQUE) { + srcAlpha *= UINT8_TO_HALF(U8_mask); + } + mask++; + } + + 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(maskRowStart) { + maskRowStart += maskRowStride; + } + } +} + +#define COMMON_COMPOSITE_OP_PROLOG() \ + while (rows > 0) { \ + \ + const half *src = reinterpret_cast(srcRowStart); \ + half *dst = reinterpret_cast(dstRowStart); \ + Q_INT32 columns = numColumns; \ + const Q_UINT8 *mask = maskRowStart; \ + \ + while (columns > 0) { \ + \ + half srcAlpha = src[PIXEL_ALPHA]; \ + half dstAlpha = dst[PIXEL_ALPHA]; \ + \ + srcAlpha = QMIN(srcAlpha, dstAlpha); \ + \ + if (mask != 0) { \ + Q_UINT8 U8_mask = *mask; \ + \ + if (U8_mask != OPACITY_OPAQUE) { \ + srcAlpha *= UINT8_TO_HALF(U8_mask); \ + } \ + mask++; \ + } \ + \ + 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(maskRowStart) { \ + maskRowStart += maskRowStride; \ + } \ + } + +void KisRgbF16HalfColorSpace::compositeMultiply(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_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(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_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 = QMIN(dstColor / (srcColor + EPSILON), HALF_MAX); + + half newColor = HALF_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbF16HalfColorSpace::compositeScreen(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_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(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_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(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_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 = QMIN(dstColor / (HALF_MAX + EPSILON - srcColor), HALF_MAX); + + half newColor = HALF_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbF16HalfColorSpace::compositeBurn(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_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 = QMIN((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(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_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 = QMIN(srcColor, dstColor); + + half newColor = HALF_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbF16HalfColorSpace::compositeLighten(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_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 = QMAX(srcColor, dstColor); + + half newColor = HALF_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbF16HalfColorSpace::compositeHue(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_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(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_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(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_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(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_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(Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowSize, + const Q_UINT8 *srcAlphaMask, + Q_INT32 maskRowStride, + Q_INT32 rows, + Q_INT32 cols, + half /*opacity*/) +{ + while (rows-- > 0) + { + const Pixel *s = reinterpret_cast(src); + Pixel *d = reinterpret_cast(dst); + const Q_UINT8 *mask = srcAlphaMask; + + for (Q_INT32 i = cols; i > 0; i--, s++, d++) + { + half srcAlpha = s->alpha; + + // apply the alphamask + if (mask != 0) { + Q_UINT8 U8_mask = *mask; + + if (U8_mask != OPACITY_OPAQUE) { + srcAlpha = HALF_BLEND(srcAlpha, F16HALF_OPACITY_OPAQUE, UINT8_TO_HALF(U8_mask)); + } + mask++; + } + d->alpha = srcAlpha * d->alpha; + } + + dst += dstRowSize; + src += srcRowSize; + if(srcAlphaMask) { + srcAlphaMask += maskRowStride; + } + } +} + +void KisRgbF16HalfColorSpace::bitBlt(Q_UINT8 *dst, + Q_INT32 dstRowStride, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 *mask, + Q_INT32 maskRowStride, + Q_UINT8 U8_opacity, + Q_INT32 rows, + Q_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, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DIVIDE: + compositeDivide(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_LIGHTEN: + compositeLighten(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_HUE: + compositeHue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_SATURATION: + compositeSaturation(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_VALUE: + compositeValue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COLOR: + compositeColor(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_OVERLAY: + compositeOverlay(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ERASE: + compositeErase(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DODGE: + compositeDodge(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_BURN: + compositeBurn(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ALPHA_DARKEN: + abstractCompositeAlphaDarken( + dst, dstRowStride, src, srcRowStride, mask, maskRowStride, + 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/krita/colorspaces/rgb_f16half/kis_rgb_f16half_colorspace.h b/krita/colorspaces/rgb_f16half/kis_rgb_f16half_colorspace.h new file mode 100644 index 00000000..c56d7f63 --- /dev/null +++ b/krita/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 * parent, KisProfile *p); + virtual ~KisRgbF16HalfColorSpace(); + + virtual bool willDegrade(ColorSpaceIndependence independence) + { + if (independence == TO_RGBA8 || independence == TO_LAB16) + return true; + else + return false; + }; + + +public: + void setPixel(Q_UINT8 *pixel, half red, half green, half blue, half alpha) const; + void getPixel(const Q_UINT8 *pixel, half *red, half *green, half *blue, half *alpha) const; + + virtual void fromQColor(const QColor& c, Q_UINT8 *dst, KisProfile * profile = 0); + virtual void fromQColor(const QColor& c, Q_UINT8 opacity, Q_UINT8 *dst, KisProfile * profile = 0); + + virtual void toQColor(const Q_UINT8 *src, QColor *c, KisProfile * profile = 0); + virtual void toQColor(const Q_UINT8 *src, QColor *c, Q_UINT8 *opacity, KisProfile * profile = 0); + + virtual Q_UINT8 difference(const Q_UINT8 *src1, const Q_UINT8 *src2); + virtual void mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const; + virtual void invertColor(Q_UINT8 * src, Q_INT32 nPixels); + virtual void convolveColors(Q_UINT8** colors, Q_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const; + virtual Q_UINT8 intensity8(const Q_UINT8 * src) const; + + virtual QValueVector channels() const; + virtual Q_UINT32 nChannels() const; + virtual Q_UINT32 nColorChannels() const; + virtual Q_UINT32 pixelSize() const; + + virtual QImage convertToQImage(const Q_UINT8 *data, Q_INT32 width, Q_INT32 height, + KisProfile * dstProfile, + Q_INT32 renderingIntent, + float exposure = 0.0f); + + virtual KisCompositeOpList userVisiblecompositeOps() const; + + +protected: + + virtual void bitBlt(Q_UINT8 *dst, + Q_INT32 dstRowStride, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 *srcAlphaMask, + Q_INT32 maskRowStride, + Q_UINT8 opacity, + Q_INT32 rows, + Q_INT32 cols, + const KisCompositeOp& op); + + void compositeOver(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, half opacity); + void compositeMultiply(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, half opacity); + void compositeDivide(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, half opacity); + void compositeScreen(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, half opacity); + void compositeOverlay(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, half opacity); + void compositeDodge(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, half opacity); + void compositeBurn(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, half opacity); + void compositeDarken(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, half opacity); + void compositeLighten(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, half opacity); + void compositeHue(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, half opacity); + void compositeSaturation(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, half opacity); + void compositeValue(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, half opacity); + void compositeColor(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, half opacity); + void compositeErase(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, half opacity); + +private: + friend class KisRgbF16HalfColorSpaceTester; + + static const Q_UINT8 PIXEL_BLUE = 0; + static const Q_UINT8 PIXEL_GREEN = 1; + static const Q_UINT8 PIXEL_RED = 2; + static const Q_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: + /** + * Krita 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 Q_UINT32 colorSpaceType() { return RGBAF16HALF_LCMS_TYPE; }; + + virtual icColorSpaceSignature colorSpaceSignature() { return icSigRgbData; }; + + virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) { return new KisRgbF16HalfColorSpace(parent, p); }; + + virtual QString defaultProfile() { return "sRGB built-in - (lcms internal)"; }; +}; + +#endif // KIS_RGB_F16HALF_COLORSPACE_H_ + diff --git a/krita/colorspaces/rgb_f16half/krita_rgb_f16half_plugin.desktop b/krita/colorspaces/rgb_f16half/krita_rgb_f16half_plugin.desktop new file mode 100644 index 00000000..8ebf7b17 --- /dev/null +++ b/krita/colorspaces/rgb_f16half/krita_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=Krita/ColorSpace +Type=Service +X-KDE-Library=krita_rgb_f16half_plugin +X-Krita-Version=2 diff --git a/krita/colorspaces/rgb_f16half/rgb_f16half_plugin.cc b/krita/colorspaces/rgb_f16half/rgb_f16half_plugin.cc new file mode 100644 index 00000000..0674cde7 --- /dev/null +++ b/krita/colorspaces/rgb_f16half/rgb_f16half_plugin.cc @@ -0,0 +1,63 @@ +/* +* rgb_f32_plugin.cc -- Part of Krita +* +* 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( krita_rgb_f16half_plugin, RGBF16HalfPluginFactory( "krita" ) ) + + +RGBF16HalfPlugin::RGBF16HalfPlugin(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(RGBF16HalfPluginFactory::instance()); + + if ( parent->inherits("KisColorSpaceFactoryRegistry") ) + { + KisColorSpaceFactoryRegistry * f = dynamic_cast( parent ); + + 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/krita/colorspaces/rgb_f16half/rgb_f16half_plugin.h b/krita/colorspaces/rgb_f16half/rgb_f16half_plugin.h new file mode 100644 index 00000000..00c361a1 --- /dev/null +++ b/krita/colorspaces/rgb_f16half/rgb_f16half_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_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 +public: + RGBF16HalfPlugin(QObject *parent, const char *name, const QStringList &); + virtual ~RGBF16HalfPlugin(); + +}; + + +#endif // RGB_F16HALF_PLUGIN_H_ diff --git a/krita/colorspaces/rgb_f16half/rgb_f16half_plugin.rc b/krita/colorspaces/rgb_f16half/rgb_f16half_plugin.rc new file mode 100644 index 00000000..0155b2c5 --- /dev/null +++ b/krita/colorspaces/rgb_f16half/rgb_f16half_plugin.rc @@ -0,0 +1,9 @@ + + +&Image + &Mode + + + + + diff --git a/krita/colorspaces/rgb_f16half/tests/Makefile.am b/krita/colorspaces/rgb_f16half/tests/Makefile.am new file mode 100644 index 00000000..4b8ff499 --- /dev/null +++ b/krita/colorspaces/rgb_f16half/tests/Makefile.am @@ -0,0 +1,19 @@ +AM_CPPFLAGS = -I$(srcdir)/.. \ + -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../kritacolor/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 ../libkrita_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/krita/colorspaces/rgb_f16half/tests/kis_rgb_f16half_colorspace_tester.cc b/krita/colorspaces/rgb_f16half/tests/kis_rgb_f16half_colorspace_tester.cc new file mode 100644 index 00000000..20f417d9 --- /dev/null +++ b/krita/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(); + testToQImage(); + 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); + + QValueVector 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->fromQColor(qRgb(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->fromQColor(qRgb(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->fromQColor(qRgb(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->fromQColor(qRgb(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->fromQColor(qRgb(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->fromQColor(qRgb(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; + + QColor c; + + cs->toQColor(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->toQColor(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->toQColor(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; + + Q_UINT8 opacity; + + cs->toQColor(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->toQColor(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->toQColor(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->toQColor(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; + + QString valueText = cs->channelValueText(reinterpret_cast(pixel), RED_CHANNEL); + CHECK(valueText, QString().setNum(CHANNEL_VALUE_ONE)); + + valueText = cs->channelValueText(reinterpret_cast(pixel), GREEN_CHANNEL); + CHECK(valueText, QString().setNum(CHANNEL_VALUE_ONE / 2)); + + valueText = cs->channelValueText(reinterpret_cast(pixel), BLUE_CHANNEL); + CHECK(valueText, QString().setNum(CHANNEL_VALUE_ONE / 4)); + + valueText = cs->channelValueText(reinterpret_cast(pixel), ALPHA_CHANNEL); + CHECK(valueText, QString().setNum(CHANNEL_VALUE_ZERO)); + + valueText = cs->normalisedChannelValueText(reinterpret_cast(pixel), RED_CHANNEL); + CHECK(valueText, QString().setNum(CHANNEL_VALUE_ONE)); + + valueText = cs->normalisedChannelValueText(reinterpret_cast(pixel), GREEN_CHANNEL); + CHECK(valueText, QString().setNum(CHANNEL_VALUE_ONE / 2)); + + valueText = cs->normalisedChannelValueText(reinterpret_cast(pixel), BLUE_CHANNEL); + CHECK(valueText, QString().setNum(CHANNEL_VALUE_ONE / 4)); + + valueText = cs->normalisedChannelValueText(reinterpret_cast(pixel), ALPHA_CHANNEL); + CHECK(valueText, QString().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 Q_UINT8 *pixelPtrs[2]; + Q_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::testToQImage() +{ + 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} + }; + + QImage image = cs->convertToQImage(reinterpret_cast(pixels), PIXELS_WIDTH, PIXELS_HEIGHT, 0, 0); + + QRgb c = image.pixel(0, 0); + + // Exposure comes into play here. + /* + CHECK(qRed(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE)); + CHECK(qGreen(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE)); + CHECK(qBlue(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE)); + CHECK(qAlpha(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE / 4)); + + c = image.pixel(1, 0); + + CHECK(qRed(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE / 3)); + CHECK(qGreen(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE / 2)); + CHECK(qBlue(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE / 4)); + CHECK(qAlpha(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE / 2)); + + c = image.pixel(0, 1); + + CHECK(qRed(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE)); + CHECK(qGreen(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE)); + CHECK(qBlue(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE)); + CHECK(qAlpha(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ZERO)); + + c = image.pixel(1, 1); + + CHECK(qRed(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ZERO)); + CHECK(qGreen(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ZERO)); + CHECK(qBlue(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ZERO)); + CHECK(qAlpha(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, (Q_UINT16)UINT8_TO_UINT16(253)); + CHECK(dstPixel.green, (Q_UINT16)UINT8_TO_UINT16(254)); + CHECK(dstPixel.blue, (Q_UINT16)UINT8_TO_UINT16(254)); + CHECK(dstPixel.alpha, KisRgbF16HalfColorSpace::F16HALF_OPACITY_OPAQUE); + + Q_UINT16 srcColor = 43690; + Q_UINT16 dstColor = 43690; + + srcColor = QMIN((dstColor * (65535u + 1u) + (srcColor / 2u)) / (1u + srcColor), 65535u); + + CHECK((int)srcColor, 65534); + + Q_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, mask, MASK_ROW_STRIDE, NUM_ROWS, NUM_COLUMNS, opacity); + */ + + delete cs; +} + diff --git a/krita/colorspaces/rgb_f16half/tests/kis_rgb_f16half_colorspace_tester.h b/krita/colorspaces/rgb_f16half/tests/kis_rgb_f16half_colorspace_tester.h new file mode 100644 index 00000000..db740fa4 --- /dev/null +++ b/krita/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(QString(__FILE__) + "[" + QString::number(__LINE__) + "]: passed " + #x); \ +} \ +else \ +{ \ + failure(QString(__FILE__) + "[" + QString::number(__LINE__) + QString("]: failed ") + #x + "\n Expected " + #y + ", Actual result " + QString::number(x)); \ +} \ + +class KisRgbF16HalfColorSpaceTester : public KUnitTest::Tester +{ +public: + void allTests(); + void testBasics(); + void testMixColors(); + void testToQImage(); + void testCompositeOps(); +}; + +#endif + diff --git a/krita/colorspaces/rgb_f32/Makefile.am b/krita/colorspaces/rgb_f32/Makefile.am new file mode 100644 index 00000000..07c65b00 --- /dev/null +++ b/krita/colorspaces/rgb_f32/Makefile.am @@ -0,0 +1,34 @@ +# Install the desktop file needed to detect the plugin +kde_services_DATA = krita_rgb_f32_plugin.desktop + +INCLUDES = \ + -I$(srcdir)/../../sdk \ + -I$(srcdir)/../../kritacolor/color_strategy/ \ + -I$(srcdir)/../../kritacolor/ \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + + +lib_LTLIBRARIES = libkrita_rgb_f32.la +libkrita_rgb_f32_la_SOURCES = kis_rgb_f32_colorspace.cc +libkrita_rgb_f32_la_LDFLAGS = $(all_libraries) +libkrita_rgb_f32_la_LIBADD = ../../kritacolor/libkritacolor.la + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = krita_rgb_f32_plugin.la + +# Srcs for the plugin +krita_rgb_f32_plugin_la_SOURCES = rgb_f32_plugin.cc +noinst_HEADERS = rgb_f32_plugin.h kis_rgb_f32_colorspace.h + +krita_rgb_f32_plugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +krita_rgb_f32_plugin_la_LIBADD = libkrita_rgb_f32.la ../../kritacolor/libkritacolor.la + +krita_rgb_f32_plugin_la_METASOURCES = AUTO + +if include_kunittest_tests +TESTSDIR = tests +endif + +SUBDIRS = . $(TESTSDIR) + diff --git a/krita/colorspaces/rgb_f32/kis_rgb_f32_colorspace.cc b/krita/colorspaces/rgb_f32/kis_rgb_f32_colorspace.cc new file mode 100644 index 00000000..7db6bd9e --- /dev/null +++ b/krita/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 Q_INT32 MAX_CHANNEL_RGB = 3; + const Q_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 * parent, KisProfile */*p*/) : + KisF32BaseColorSpace(KisID("RGBAF32", i18n("RGB (32-bit float/channel)")), F32_LCMS_TYPE, icSigRgbData, parent, 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(Q_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 Q_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::fromQColor(const QColor& c, Q_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::fromQColor(const QColor& c, Q_UINT8 opacity, Q_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::toQColor(const Q_UINT8 *srcU8, QColor *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::toQColor(const Q_UINT8 *srcU8, QColor *c, Q_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); +} + +Q_UINT8 KisRgbF32ColorSpace::difference(const Q_UINT8 *src1U8, const Q_UINT8 *src2U8) +{ + const Pixel *src1 = reinterpret_cast(src1U8); + const Pixel *src2 = reinterpret_cast(src2U8); + + return FLOAT_TO_UINT8(QMAX(QABS(src2->red - src1->red), + QMAX(QABS(src2->green - src1->green), + QABS(src2->blue - src1->blue)))); +} + +void KisRgbF32ColorSpace::mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_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(Q_UINT8** colors, Q_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_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(Q_UINT8 * src, Q_INT32 nPixels) +{ + Q_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; + } + +} + +Q_UINT8 KisRgbF32ColorSpace::intensity8(const Q_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); +} + + + +QValueVector KisRgbF32ColorSpace::channels() const +{ + return m_channels; +} + +Q_UINT32 KisRgbF32ColorSpace::nChannels() const +{ + return MAX_CHANNEL_RGBA; +} + +Q_UINT32 KisRgbF32ColorSpace::nColorChannels() const +{ + return MAX_CHANNEL_RGB; +} + +Q_UINT32 KisRgbF32ColorSpace::pixelSize() const +{ + return MAX_CHANNEL_RGBA * sizeof(float); +} + +Q_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); +} + +QImage KisRgbF32ColorSpace::convertToQImage(const Q_UINT8 *dataU8, Q_INT32 width, Q_INT32 height, + KisProfile * /*dstProfile*/, + Q_INT32 /*renderingIntent*/, float exposure) + +{ + const float *data = reinterpret_cast(dataU8); + + QImage img = QImage(width, height, 32, 0, QImage::LittleEndian); + img.setAlphaBuffer(true); + + Q_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(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, float opacity) +{ + while (rows > 0) { + + const float *src = reinterpret_cast(srcRowStart); + float *dst = reinterpret_cast(dstRowStart); + const Q_UINT8 *mask = maskRowStart; + Q_INT32 columns = numColumns; + + while (columns > 0) { + + float srcAlpha = src[PIXEL_ALPHA]; + + // apply the alphamask + if (mask != 0) { + Q_UINT8 U8_mask = *mask; + + if (U8_mask != OPACITY_OPAQUE) { + srcAlpha *= UINT8_TO_FLOAT(U8_mask); + } + mask++; + } + + 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(maskRowStart) { + maskRowStart += maskRowStride; + } + } +} + +#define COMMON_COMPOSITE_OP_PROLOG() \ + while (rows > 0) { \ + \ + const float *src = reinterpret_cast(srcRowStart); \ + float *dst = reinterpret_cast(dstRowStart); \ + Q_INT32 columns = numColumns; \ + const Q_UINT8 *mask = maskRowStart; \ + \ + while (columns > 0) { \ + \ + float srcAlpha = src[PIXEL_ALPHA]; \ + float dstAlpha = dst[PIXEL_ALPHA]; \ + \ + srcAlpha = QMIN(srcAlpha, dstAlpha); \ + \ + if (mask != 0) { \ + Q_UINT8 U8_mask = *mask; \ + \ + if (U8_mask != OPACITY_OPAQUE) { \ + srcAlpha *= UINT8_TO_FLOAT(U8_mask); \ + } \ + mask++; \ + } \ + \ + 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(maskRowStart) { \ + maskRowStart += maskRowStride; \ + } \ + } + +void KisRgbF32ColorSpace::compositeMultiply(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_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(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_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 = QMIN(dstColor / (srcColor + EPSILON), FLOAT_MAX); + + float newColor = FLOAT_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbF32ColorSpace::compositeScreen(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_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(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_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(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_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 = QMIN(dstColor / (FLOAT_MAX + EPSILON - srcColor), FLOAT_MAX); + + float newColor = FLOAT_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbF32ColorSpace::compositeBurn(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_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 = QMIN((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(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_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 = QMIN(srcColor, dstColor); + + float newColor = FLOAT_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbF32ColorSpace::compositeLighten(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_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 = QMAX(srcColor, dstColor); + + float newColor = FLOAT_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbF32ColorSpace::compositeHue(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_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(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_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(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_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(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_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(Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowSize, + const Q_UINT8 *srcAlphaMask, + Q_INT32 maskRowStride, + Q_INT32 rows, + Q_INT32 cols, + float /*opacity*/) +{ + while (rows-- > 0) + { + const Pixel *s = reinterpret_cast(src); + Pixel *d = reinterpret_cast(dst); + const Q_UINT8 *mask = srcAlphaMask; + + for (Q_INT32 i = cols; i > 0; i--, s++, d++) + { + float srcAlpha = s->alpha; + + // apply the alphamask + if (mask != 0) { + Q_UINT8 U8_mask = *mask; + + if (U8_mask != OPACITY_OPAQUE) { + srcAlpha = FLOAT_BLEND(srcAlpha, F32_OPACITY_OPAQUE, UINT8_TO_FLOAT(U8_mask)); + } + mask++; + } + d->alpha = srcAlpha * d->alpha; + } + + dst += dstRowSize; + src += srcRowSize; + if(srcAlphaMask) { + srcAlphaMask += maskRowStride; + } + } +} + +void KisRgbF32ColorSpace::bitBlt(Q_UINT8 *dst, + Q_INT32 dstRowStride, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 *mask, + Q_INT32 maskRowStride, + Q_UINT8 U8_opacity, + Q_INT32 rows, + Q_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, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DIVIDE: + compositeDivide(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_LIGHTEN: + compositeLighten(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_HUE: + compositeHue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_SATURATION: + compositeSaturation(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_VALUE: + compositeValue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COLOR: + compositeColor(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_OVERLAY: + compositeOverlay(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ERASE: + compositeErase(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DODGE: + compositeDodge(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_BURN: + compositeBurn(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ALPHA_DARKEN: + abstractCompositeAlphaDarken( + dst, dstRowStride, src, srcRowStride, mask, maskRowStride, + 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/krita/colorspaces/rgb_f32/kis_rgb_f32_colorspace.h b/krita/colorspaces/rgb_f32/kis_rgb_f32_colorspace.h new file mode 100644 index 00000000..a1681be5 --- /dev/null +++ b/krita/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 * parent, KisProfile *p); + virtual ~KisRgbF32ColorSpace(); + + virtual bool willDegrade(ColorSpaceIndependence independence) + { + if (independence == TO_RGBA8 || independence == TO_LAB16) + return true; + else + return false; + }; + + + +public: + void setPixel(Q_UINT8 *pixel, float red, float green, float blue, float alpha) const; + void getPixel(const Q_UINT8 *pixel, float *red, float *green, float *blue, float *alpha) const; + + virtual void fromQColor(const QColor& c, Q_UINT8 *dst, KisProfile * profile = 0); + virtual void fromQColor(const QColor& c, Q_UINT8 opacity, Q_UINT8 *dst, KisProfile * profile = 0); + + virtual void toQColor(const Q_UINT8 *src, QColor *c, KisProfile * profile = 0); + virtual void toQColor(const Q_UINT8 *src, QColor *c, Q_UINT8 *opacity, KisProfile * profile = 0); + + virtual Q_UINT8 difference(const Q_UINT8 *src1, const Q_UINT8 *src2); + virtual void mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const; + virtual void invertColor(Q_UINT8 * src, Q_INT32 nPixels); + virtual void convolveColors(Q_UINT8** colors, Q_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const; + virtual Q_UINT8 intensity8(const Q_UINT8 * src) const; + + virtual QValueVector channels() const; + virtual Q_UINT32 nChannels() const; + virtual Q_UINT32 nColorChannels() const; + virtual Q_UINT32 pixelSize() const; + + + virtual QImage convertToQImage(const Q_UINT8 *data, Q_INT32 width, Q_INT32 height, + KisProfile * dstProfile, + Q_INT32 renderingIntent, + float exposure = 0.0f); + + virtual KisCompositeOpList userVisiblecompositeOps() const; + + +protected: + + virtual void bitBlt(Q_UINT8 *dst, + Q_INT32 dstRowStride, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 *srcAlphaMask, + Q_INT32 maskRowStride, + Q_UINT8 opacity, + Q_INT32 rows, + Q_INT32 cols, + const KisCompositeOp& op); + + void compositeOver(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity); + void compositeMultiply(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity); + void compositeDivide(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity); + void compositeScreen(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity); + void compositeOverlay(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity); + void compositeDodge(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity); + void compositeBurn(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity); + void compositeDarken(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity); + void compositeLighten(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity); + void compositeHue(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity); + void compositeSaturation(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity); + void compositeValue(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity); + void compositeColor(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity); + void compositeErase(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity); + +private: + friend class KisRgbF32ColorSpaceTester; + + static const Q_UINT8 PIXEL_BLUE = 0; + static const Q_UINT8 PIXEL_GREEN = 1; + static const Q_UINT8 PIXEL_RED = 2; + static const Q_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 Q_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: + /** + * Krita 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 Q_UINT32 colorSpaceType() { return F32_LCMS_TYPE; }; + + virtual icColorSpaceSignature colorSpaceSignature() { return icSigRgbData; }; + + virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) { return new KisRgbF32ColorSpace(parent, p); }; + + virtual QString defaultProfile() { return "sRGB built-in - (lcms internal)"; }; +}; + +#endif // KIS_STRATEGY_COLORSPACE_RGB_F32_H_ + diff --git a/krita/colorspaces/rgb_f32/krita_rgb_f32_plugin.desktop b/krita/colorspaces/rgb_f32/krita_rgb_f32_plugin.desktop new file mode 100644 index 00000000..67ea396d --- /dev/null +++ b/krita/colorspaces/rgb_f32/krita_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=Krita/ColorSpace +Type=Service +X-Krita-Version=2 +X-KDE-Library=krita_rgb_f32_plugin diff --git a/krita/colorspaces/rgb_f32/rgb_f32_plugin.cc b/krita/colorspaces/rgb_f32/rgb_f32_plugin.cc new file mode 100644 index 00000000..01dc514a --- /dev/null +++ b/krita/colorspaces/rgb_f32/rgb_f32_plugin.cc @@ -0,0 +1,63 @@ +/* +* rgb_f32_plugin.cc -- Part of Krita +* +* 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( krita_rgb_f32_plugin, RGBF32PluginFactory( "krita" ) ) + + +RGBF32Plugin::RGBF32Plugin(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(RGBF32PluginFactory::instance()); + + if ( parent->inherits("KisColorSpaceFactoryRegistry") ) + { + KisColorSpaceFactoryRegistry * f = dynamic_cast(parent); + + 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/krita/colorspaces/rgb_f32/rgb_f32_plugin.h b/krita/colorspaces/rgb_f32/rgb_f32_plugin.h new file mode 100644 index 00000000..f847dc3d --- /dev/null +++ b/krita/colorspaces/rgb_f32/rgb_f32_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_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 +public: + RGBF32Plugin(QObject *parent, const char *name, const QStringList &); + virtual ~RGBF32Plugin(); + +}; + + +#endif // RGB_F32_PLUGIN_H_ diff --git a/krita/colorspaces/rgb_f32/rgb_f32_plugin.rc b/krita/colorspaces/rgb_f32/rgb_f32_plugin.rc new file mode 100644 index 00000000..14aab641 --- /dev/null +++ b/krita/colorspaces/rgb_f32/rgb_f32_plugin.rc @@ -0,0 +1,9 @@ + + +&Image + &Mode + + + + + diff --git a/krita/colorspaces/rgb_f32/tests/Makefile.am b/krita/colorspaces/rgb_f32/tests/Makefile.am new file mode 100644 index 00000000..943af1d0 --- /dev/null +++ b/krita/colorspaces/rgb_f32/tests/Makefile.am @@ -0,0 +1,17 @@ +AM_CPPFLAGS = -I$(srcdir)/.. \ + -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../kritacolor/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 ../libkrita_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/krita/colorspaces/rgb_f32/tests/kis_strategy_colorspace_rgb_f32_tester.cc b/krita/colorspaces/rgb_f32/tests/kis_strategy_colorspace_rgb_f32_tester.cc new file mode 100644 index 00000000..5694f3e3 --- /dev/null +++ b/krita/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(); + testToQImage(); + 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); + + QValueVector 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->fromQColor(qRgb(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->fromQColor(qRgb(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->fromQColor(qRgb(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->fromQColor(qRgb(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->fromQColor(qRgb(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->fromQColor(qRgb(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; + + QColor c; + + cs->toQColor(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->toQColor(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->toQColor(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; + + Q_UINT8 opacity; + + cs->toQColor(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->toQColor(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->toQColor(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->toQColor(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; + + QString valueText = cs->channelValueText(reinterpret_cast(pixel), RED_CHANNEL); + CHECK(valueText, QString().setNum(MAX_CHANNEL_VALUE)); + + valueText = cs->channelValueText(reinterpret_cast(pixel), GREEN_CHANNEL); + CHECK(valueText, QString().setNum(MAX_CHANNEL_VALUE / 2)); + + valueText = cs->channelValueText(reinterpret_cast(pixel), BLUE_CHANNEL); + CHECK(valueText, QString().setNum(MAX_CHANNEL_VALUE / 4)); + + valueText = cs->channelValueText(reinterpret_cast(pixel), ALPHA_CHANNEL); + CHECK(valueText, QString().setNum(MIN_CHANNEL_VALUE)); + + valueText = cs->normalisedChannelValueText(reinterpret_cast(pixel), RED_CHANNEL); + CHECK(valueText, QString().setNum(MAX_CHANNEL_VALUE)); + + valueText = cs->normalisedChannelValueText(reinterpret_cast(pixel), GREEN_CHANNEL); + CHECK(valueText, QString().setNum(MAX_CHANNEL_VALUE / 2)); + + valueText = cs->normalisedChannelValueText(reinterpret_cast(pixel), BLUE_CHANNEL); + CHECK(valueText, QString().setNum(MAX_CHANNEL_VALUE / 4)); + + valueText = cs->normalisedChannelValueText(reinterpret_cast(pixel), ALPHA_CHANNEL); + CHECK(valueText, QString().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 Q_UINT8 *pixelPtrs[2]; + Q_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::testToQImage() +{ + 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} + }; + + QImage image = cs->convertToQImage(reinterpret_cast(pixels), PIXELS_WIDTH, PIXELS_HEIGHT, 0, 0); + + QRgb c = image.pixel(0, 0); + + // Exposure comes into play here. + /* + CHECK(qRed(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE)); + CHECK(qGreen(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE)); + CHECK(qBlue(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE)); + CHECK(qAlpha(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE / 4)); + + c = image.pixel(1, 0); + + CHECK(qRed(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE / 3)); + CHECK(qGreen(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE / 2)); + CHECK(qBlue(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE / 4)); + CHECK(qAlpha(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE / 2)); + + c = image.pixel(0, 1); + + CHECK(qRed(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE)); + CHECK(qGreen(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE)); + CHECK(qBlue(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE)); + CHECK(qAlpha(c), (int)FLOAT_TO_UINT8(MIN_CHANNEL_VALUE)); + + c = image.pixel(1, 1); + + CHECK(qRed(c), (int)FLOAT_TO_UINT8(MIN_CHANNEL_VALUE)); + CHECK(qGreen(c), (int)FLOAT_TO_UINT8(MIN_CHANNEL_VALUE)); + CHECK(qBlue(c), (int)FLOAT_TO_UINT8(MIN_CHANNEL_VALUE)); + CHECK(qAlpha(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, (Q_UINT16)UINT8_TO_UINT16(253)); + CHECK(dstPixel.green, (Q_UINT16)UINT8_TO_UINT16(254)); + CHECK(dstPixel.blue, (Q_UINT16)UINT8_TO_UINT16(254)); + CHECK(dstPixel.alpha, KisRgbF32ColorSpace::F32_OPACITY_OPAQUE); + + Q_UINT16 srcColor = 43690; + Q_UINT16 dstColor = 43690; + + srcColor = QMIN((dstColor * (65535u + 1u) + (srcColor / 2u)) / (1u + srcColor), 65535u); + + CHECK((int)srcColor, 65534); + + Q_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, mask, MASK_ROW_STRIDE, NUM_ROWS, NUM_COLUMNS, opacity); + */ + + delete cs; +} + diff --git a/krita/colorspaces/rgb_f32/tests/kis_strategy_colorspace_rgb_f32_tester.h b/krita/colorspaces/rgb_f32/tests/kis_strategy_colorspace_rgb_f32_tester.h new file mode 100644 index 00000000..d6e47704 --- /dev/null +++ b/krita/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(QString(__FILE__) + "[" + QString::number(__LINE__) + "]: passed " + #x); \ +} \ +else \ +{ \ + failure(QString(__FILE__) + "[" + QString::number(__LINE__) + QString("]: failed ") + #x + "\n Expected " + #y + ", Actual result " + QString::number(x)); \ +} \ + +class KisRgbF32ColorSpaceTester : public KUnitTest::Tester +{ +public: + void allTests(); + void testBasics(); + void testMixColors(); + void testToQImage(); + void testCompositeOps(); +}; + +#endif + diff --git a/krita/colorspaces/rgb_u16/Makefile.am b/krita/colorspaces/rgb_u16/Makefile.am new file mode 100644 index 00000000..927debfa --- /dev/null +++ b/krita/colorspaces/rgb_u16/Makefile.am @@ -0,0 +1,32 @@ +# location for the rc file +kde_services_DATA = krita_rgb_u16_plugin.desktop + +INCLUDES = -I$(srcdir)/../../sdk \ + -I$(srcdir)/../../kritacolor/color_strategy/ \ + -I$(srcdir)/../../kritacolor \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +lib_LTLIBRARIES = libkrita_rgb_u16.la +libkrita_rgb_u16_la_SOURCES = kis_rgb_u16_colorspace.cc +libkrita_rgb_u16_la_LDFLAGS = $(all_libraries) +libkrita_rgb_u16_la_LIBADD = ../../kritacolor/libkritacolor.la + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = krita_rgb_u16_plugin.la + +# Srcs for the plugin +krita_rgb_u16_plugin_la_SOURCES = rgb_u16_plugin.cc +noinst_HEADERS = rgb_u16_plugin.h kis_rgb_u16_colorspace.h + +krita_rgb_u16_plugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +krita_rgb_u16_plugin_la_LIBADD = libkrita_rgb_u16.la ../../kritacolor/libkritacolor.la + +krita_rgb_u16_plugin_la_METASOURCES = AUTO + +if include_kunittest_tests +TESTSDIR = tests +endif + +SUBDIRS = . $(TESTSDIR) + diff --git a/krita/colorspaces/rgb_u16/kis_rgb_u16_colorspace.cc b/krita/colorspaces/rgb_u16/kis_rgb_u16_colorspace.cc new file mode 100644 index 00000000..7ec94671 --- /dev/null +++ b/krita/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 Q_INT32 MAX_CHANNEL_RGB = 3; + const Q_INT32 MAX_CHANNEL_RGBA = 4; +} + +// XXX: already defined is superclass? +//const Q_UINT16 KisRgbU16ColorSpace::U16_OPACITY_OPAQUE; +//const Q_UINT16 KisRgbU16ColorSpace::U16_OPACITY_TRANSPARENT; + +KisRgbU16ColorSpace::KisRgbU16ColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) : + KisU16BaseColorSpace(KisID("RGBA16", i18n("RGB (16-bit integer/channel)")), TYPE_BGRA_16, icSigRgbData, parent, p) +{ + m_channels.push_back(new KisChannelInfo(i18n("Red"), i18n("R"), PIXEL_RED * sizeof(Q_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(Q_UINT16), QColor(255,0,0))); + m_channels.push_back(new KisChannelInfo(i18n("Green"), i18n("G"), PIXEL_GREEN * sizeof(Q_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(Q_UINT16), QColor(0,255,0))); + m_channels.push_back(new KisChannelInfo(i18n("Blue"), i18n("B"), PIXEL_BLUE * sizeof(Q_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(Q_UINT16), QColor(0,0,255))); + m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), PIXEL_ALPHA * sizeof(Q_UINT16), KisChannelInfo::ALPHA, KisChannelInfo::UINT16, sizeof(Q_UINT16))); + + m_alphaPos = PIXEL_ALPHA * sizeof(Q_UINT16); + + init(); +} + +KisRgbU16ColorSpace::~KisRgbU16ColorSpace() +{ +} + +void KisRgbU16ColorSpace::setPixel(Q_UINT8 *dst, Q_UINT16 red, Q_UINT16 green, Q_UINT16 blue, Q_UINT16 alpha) const +{ + Pixel *dstPixel = reinterpret_cast(dst); + + dstPixel->red = red; + dstPixel->green = green; + dstPixel->blue = blue; + dstPixel->alpha = alpha; +} + +void KisRgbU16ColorSpace::getPixel(const Q_UINT8 *src, Q_UINT16 *red, Q_UINT16 *green, Q_UINT16 *blue, Q_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 Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const +{ + Q_UINT32 totalRed = 0, totalGreen = 0, totalBlue = 0, newAlpha = 0; + + while (nColors--) + { + const Pixel *pixel = reinterpret_cast(*colors); + + Q_UINT32 alpha = pixel->alpha; + Q_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(Q_UINT8** colors, Q_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, + Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const +{ + Q_INT32 totalRed = 0, totalGreen = 0, totalBlue = 0, totalAlpha = 0; + + while (nColors--) + { + const Pixel * pixel = reinterpret_cast( *colors ); + + Q_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, Q_UINT16_MAX); + p->green = CLAMP( ( totalGreen / factor) + offset, 0, Q_UINT16_MAX); + p->blue = CLAMP( ( totalBlue / factor) + offset, 0, Q_UINT16_MAX); + } + if (channelFlags & KisChannelInfo::FLAG_ALPHA) { + p->alpha = CLAMP((totalAlpha/ factor) + offset, 0, Q_UINT16_MAX); + } +} + + +void KisRgbU16ColorSpace::invertColor(Q_UINT8 * src, Q_INT32 nPixels) +{ + Q_UINT32 psize = pixelSize(); + + while (nPixels--) + { + Pixel * p = reinterpret_cast< Pixel *>( src ); + p->red = Q_UINT16_MAX - p->red; + p->green = Q_UINT16_MAX - p->green; + p->blue = Q_UINT16_MAX - p->blue; + src += psize; + } +} + +Q_UINT8 KisRgbU16ColorSpace::intensity8(const Q_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)); +} + + +QValueVector KisRgbU16ColorSpace::channels() const +{ + return m_channels; +} + +Q_UINT32 KisRgbU16ColorSpace::nChannels() const +{ + return MAX_CHANNEL_RGBA; +} + +Q_UINT32 KisRgbU16ColorSpace::nColorChannels() const +{ + return MAX_CHANNEL_RGB; +} + +Q_UINT32 KisRgbU16ColorSpace::pixelSize() const +{ + return MAX_CHANNEL_RGBA * sizeof(Q_UINT16); +} + + +void KisRgbU16ColorSpace::compositeOver(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + while (rows > 0) { + + const Q_UINT16 *src = reinterpret_cast(srcRowStart); + Q_UINT16 *dst = reinterpret_cast(dstRowStart); + const Q_UINT8 *mask = maskRowStart; + Q_INT32 columns = numColumns; + + while (columns > 0) { + + Q_UINT16 srcAlpha = src[PIXEL_ALPHA]; + + // apply the alphamask + if (mask != 0) { + Q_UINT8 U8_mask = *mask; + + if (U8_mask != OPACITY_OPAQUE) { + srcAlpha = UINT16_MULT(srcAlpha, UINT8_TO_UINT16(U8_mask)); + } + mask++; + } + + 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(Q_UINT16)); + } else { + Q_UINT16 dstAlpha = dst[PIXEL_ALPHA]; + + Q_UINT16 srcBlend; + + if (dstAlpha == U16_OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + Q_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(Q_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(maskRowStart) { + maskRowStart += maskRowStride; + } + } +} + +#define COMMON_COMPOSITE_OP_PROLOG() \ + while (rows > 0) { \ + \ + const Q_UINT16 *src = reinterpret_cast(srcRowStart); \ + Q_UINT16 *dst = reinterpret_cast(dstRowStart); \ + Q_INT32 columns = numColumns; \ + const Q_UINT8 *mask = maskRowStart; \ + \ + while (columns > 0) { \ + \ + Q_UINT16 srcAlpha = src[PIXEL_ALPHA]; \ + Q_UINT16 dstAlpha = dst[PIXEL_ALPHA]; \ + \ + srcAlpha = QMIN(srcAlpha, dstAlpha); \ + \ + if (mask != 0) { \ + Q_UINT8 U8_mask = *mask; \ + \ + if (U8_mask != OPACITY_OPAQUE) { \ + srcAlpha = UINT16_MULT(srcAlpha, UINT8_TO_UINT16(U8_mask)); \ + } \ + mask++; \ + } \ + \ + if (srcAlpha != U16_OPACITY_TRANSPARENT) { \ + \ + if (opacity != U16_OPACITY_OPAQUE) { \ + srcAlpha = UINT16_MULT(srcAlpha, opacity); \ + } \ + \ + Q_UINT16 srcBlend; \ + \ + if (dstAlpha == U16_OPACITY_OPAQUE) { \ + srcBlend = srcAlpha; \ + } else { \ + Q_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(maskRowStart) { \ + maskRowStart += maskRowStride; \ + } \ + } + +void KisRgbU16ColorSpace::compositeMultiply(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + Q_UINT16 srcColor = src[channel]; + Q_UINT16 dstColor = dst[channel]; + + srcColor = UINT16_MULT(srcColor, dstColor); + + dst[channel] = UINT16_BLEND(srcColor, dstColor, srcBlend); + + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbU16ColorSpace::compositeDivide(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + Q_UINT16 srcColor = src[channel]; + Q_UINT16 dstColor = dst[channel]; + + srcColor = QMIN((dstColor * (UINT16_MAX + 1u) + (srcColor / 2u)) / (1u + srcColor), UINT16_MAX); + + Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbU16ColorSpace::compositeScreen(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + Q_UINT16 srcColor = src[channel]; + Q_UINT16 dstColor = dst[channel]; + + srcColor = UINT16_MAX - UINT16_MULT(UINT16_MAX - dstColor, UINT16_MAX - srcColor); + + Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbU16ColorSpace::compositeOverlay(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + Q_UINT16 srcColor = src[channel]; + Q_UINT16 dstColor = dst[channel]; + + srcColor = UINT16_MULT(dstColor, dstColor + 2u * UINT16_MULT(srcColor, UINT16_MAX - dstColor)); + + Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbU16ColorSpace::compositeDodge(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + Q_UINT16 srcColor = src[channel]; + Q_UINT16 dstColor = dst[channel]; + + srcColor = QMIN((dstColor * (UINT16_MAX + 1u)) / (UINT16_MAX + 1u - srcColor), UINT16_MAX); + + Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbU16ColorSpace::compositeBurn(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + Q_UINT16 srcColor = src[channel]; + Q_UINT16 dstColor = dst[channel]; + + srcColor = kMin(((UINT16_MAX - dstColor) * (UINT16_MAX + 1u)) / (srcColor + 1u), UINT16_MAX); + srcColor = kClamp(UINT16_MAX - srcColor, 0u, UINT16_MAX); + + Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbU16ColorSpace::compositeDarken(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + Q_UINT16 srcColor = src[channel]; + Q_UINT16 dstColor = dst[channel]; + + srcColor = QMIN(srcColor, dstColor); + + Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbU16ColorSpace::compositeLighten(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + Q_UINT16 srcColor = src[channel]; + Q_UINT16 dstColor = dst[channel]; + + srcColor = QMAX(srcColor, dstColor); + + Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbU16ColorSpace::compositeHue(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_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; + + Q_UINT16 dstRed = dst[PIXEL_RED]; + Q_UINT16 dstGreen = dst[PIXEL_GREEN]; + Q_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); + + Q_UINT16 srcRed = static_cast(FSrcRed * UINT16_MAX + 0.5); + Q_UINT16 srcGreen = static_cast(FSrcGreen * UINT16_MAX + 0.5); + Q_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(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_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; + + Q_UINT16 dstRed = dst[PIXEL_RED]; + Q_UINT16 dstGreen = dst[PIXEL_GREEN]; + Q_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); + + Q_UINT16 srcRed = static_cast(FSrcRed * UINT16_MAX + 0.5); + Q_UINT16 srcGreen = static_cast(FSrcGreen * UINT16_MAX + 0.5); + Q_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(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_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; + + Q_UINT16 dstRed = dst[PIXEL_RED]; + Q_UINT16 dstGreen = dst[PIXEL_GREEN]; + Q_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); + + Q_UINT16 srcRed = static_cast(FSrcRed * UINT16_MAX + 0.5); + Q_UINT16 srcGreen = static_cast(FSrcGreen * UINT16_MAX + 0.5); + Q_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(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_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; + + Q_UINT16 dstRed = dst[PIXEL_RED]; + Q_UINT16 dstGreen = dst[PIXEL_GREEN]; + Q_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); + + Q_UINT16 srcRed = static_cast(FSrcRed * UINT16_MAX + 0.5); + Q_UINT16 srcGreen = static_cast(FSrcGreen * UINT16_MAX + 0.5); + Q_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(Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowSize, + const Q_UINT8 *srcAlphaMask, + Q_INT32 maskRowStride, + Q_INT32 rows, + Q_INT32 cols, + Q_UINT16 /*opacity*/) +{ + while (rows-- > 0) + { + const Pixel *s = reinterpret_cast(src); + Pixel *d = reinterpret_cast(dst); + const Q_UINT8 *mask = srcAlphaMask; + + for (Q_INT32 i = cols; i > 0; i--, s++, d++) + { + Q_UINT16 srcAlpha = s->alpha; + + // apply the alphamask + if (mask != 0) { + Q_UINT8 U8_mask = *mask; + + if (U8_mask != OPACITY_OPAQUE) { + srcAlpha = UINT16_BLEND(srcAlpha, U16_OPACITY_OPAQUE, UINT8_TO_UINT16(U8_mask)); + } + mask++; + } + d->alpha = UINT16_MULT(srcAlpha, d->alpha); + } + + dst += dstRowSize; + src += srcRowSize; + if(srcAlphaMask) { + srcAlphaMask += maskRowStride; + } + } +} + +void KisRgbU16ColorSpace::bitBlt(Q_UINT8 *dst, + Q_INT32 dstRowStride, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 *mask, + Q_INT32 maskRowStride, + Q_UINT8 U8_opacity, + Q_INT32 rows, + Q_INT32 cols, + const KisCompositeOp& op) +{ + Q_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, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DIVIDE: + compositeDivide(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_LIGHTEN: + compositeLighten(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_HUE: + compositeHue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_SATURATION: + compositeSaturation(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_VALUE: + compositeValue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COLOR: + compositeColor(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_OVERLAY: + compositeOverlay(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ERASE: + compositeErase(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DODGE: + compositeDodge(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_BURN: + compositeBurn(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ALPHA_DARKEN: + abstractCompositeAlphaDarken( + dst, dstRowStride, src, srcRowStride, mask, maskRowStride, + 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/krita/colorspaces/rgb_u16/kis_rgb_u16_colorspace.h b/krita/colorspaces/rgb_u16/kis_rgb_u16_colorspace.h new file mode 100644 index 00000000..73a79eb3 --- /dev/null +++ b/krita/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 { + Q_UINT16 blue; + Q_UINT16 green; + Q_UINT16 red; + Q_UINT16 alpha; + }; +public: + KisRgbU16ColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p); + virtual ~KisRgbU16ColorSpace(); + + virtual bool willDegrade(ColorSpaceIndependence independence) + { + if (independence == TO_RGBA8) + return true; + else + return false; + }; + + + +public: + void setPixel(Q_UINT8 *pixel, Q_UINT16 red, Q_UINT16 green, Q_UINT16 blue, Q_UINT16 alpha) const; + void getPixel(const Q_UINT8 *pixel, Q_UINT16 *red, Q_UINT16 *green, Q_UINT16 *blue, Q_UINT16 *alpha) const; + + virtual void mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const; + virtual void convolveColors(Q_UINT8** colors, Q_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const; + virtual void invertColor(Q_UINT8 * src, Q_INT32 nPixels); + virtual Q_UINT8 intensity8(const Q_UINT8 * src) const; + + virtual QValueVector channels() const; + virtual Q_UINT32 nChannels() const; + virtual Q_UINT32 nColorChannels() const; + virtual Q_UINT32 pixelSize() const; + + virtual KisCompositeOpList userVisiblecompositeOps() const; + +protected: + + virtual void bitBlt(Q_UINT8 *dst, + Q_INT32 dstRowStride, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 *srcAlphaMask, + Q_INT32 maskRowStride, + Q_UINT8 opacity, + Q_INT32 rows, + Q_INT32 cols, + const KisCompositeOp& op); + + void compositeOver(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeMultiply(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeDivide(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeScreen(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeOverlay(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeDodge(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeBurn(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeDarken(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeLighten(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeHue(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeSaturation(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeValue(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeColor(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeErase(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + +private: + friend class KisRgbU16ColorSpaceTester; + + static const Q_UINT8 PIXEL_BLUE = 0; + static const Q_UINT8 PIXEL_GREEN = 1; + static const Q_UINT8 PIXEL_RED = 2; + static const Q_UINT8 PIXEL_ALPHA = 3; +}; + +class KisRgbU16ColorSpaceFactory : public KisColorSpaceFactory +{ +public: + /** + * Krita 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 Q_UINT32 colorSpaceType() { return TYPE_BGRA_16; }; + + virtual icColorSpaceSignature colorSpaceSignature() { return icSigRgbData; }; + + virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) { return new KisRgbU16ColorSpace(parent, p); }; + + virtual QString defaultProfile() { return "sRGB built-in - (lcms internal)"; }; +}; + +#endif // KIS_STRATEGY_COLORSPACE_RGB_U16_H_ diff --git a/krita/colorspaces/rgb_u16/krita_rgb_u16_plugin.desktop b/krita/colorspaces/rgb_u16/krita_rgb_u16_plugin.desktop new file mode 100644 index 00000000..4cf76766 --- /dev/null +++ b/krita/colorspaces/rgb_u16/krita_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=Krita/ColorSpace +Type=Service +X-KDE-Library=krita_rgb_u16_plugin +X-Krita-Version=2 + diff --git a/krita/colorspaces/rgb_u16/rgb_u16_plugin.cc b/krita/colorspaces/rgb_u16/rgb_u16_plugin.cc new file mode 100644 index 00000000..0f88b158 --- /dev/null +++ b/krita/colorspaces/rgb_u16/rgb_u16_plugin.cc @@ -0,0 +1,61 @@ +/* +* rgb_u16_plugin.cc -- Part of Krita +* +* 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( krita_rgb_u16_plugin, RGBU16PluginFactory( "krita" ) ) + + +RGBU16Plugin::RGBU16Plugin(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(RGBU16PluginFactory::instance()); + + if ( parent->inherits("KisColorSpaceFactoryRegistry") ) + { + KisColorSpaceFactoryRegistry * f = dynamic_cast( parent ); + + 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/krita/colorspaces/rgb_u16/rgb_u16_plugin.h b/krita/colorspaces/rgb_u16/rgb_u16_plugin.h new file mode 100644 index 00000000..643833ce --- /dev/null +++ b/krita/colorspaces/rgb_u16/rgb_u16_plugin.h @@ -0,0 +1,36 @@ +/* + * 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 +public: + RGBU16Plugin(QObject *parent, const char *name, const QStringList &); + virtual ~RGBU16Plugin(); +}; + + +#endif // RGB_U16_PLUGIN_H_ diff --git a/krita/colorspaces/rgb_u16/tests/Makefile.am b/krita/colorspaces/rgb_u16/tests/Makefile.am new file mode 100644 index 00000000..f8c8dc36 --- /dev/null +++ b/krita/colorspaces/rgb_u16/tests/Makefile.am @@ -0,0 +1,17 @@ +AM_CPPFLAGS = -I$(srcdir)/.. \ + -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../kritacolor/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 ../libkrita_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/krita/colorspaces/rgb_u16/tests/kis_strategy_colorspace_rgb_u16_tester.cc b/krita/colorspaces/rgb_u16/tests/kis_strategy_colorspace_rgb_u16_tester.cc new file mode 100644 index 00000000..b41d46bc --- /dev/null +++ b/krita/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(); + testToQImage(); + 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); + + QValueVector 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); + + Q_UINT16 pixel[NUM_CHANNELS]; + + cs->fromQColor(qRgb(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->fromQColor(qRgb(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->fromQColor(qRgb(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->fromQColor(qRgb(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->fromQColor(qRgb(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->fromQColor(qRgb(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; + + QColor c; + + cs->toQColor(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->toQColor(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->toQColor(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; + + Q_UINT8 opacity; + + cs->toQColor(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->toQColor(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->toQColor(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->toQColor(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; + + QString valueText = cs->channelValueText(reinterpret_cast(pixel), RED_CHANNEL); + CHECK(valueText, QString().setNum(MAX_CHANNEL_VALUE)); + + valueText = cs->channelValueText(reinterpret_cast(pixel), GREEN_CHANNEL); + CHECK(valueText, QString().setNum(MAX_CHANNEL_VALUE / 2)); + + valueText = cs->channelValueText(reinterpret_cast(pixel), BLUE_CHANNEL); + CHECK(valueText, QString().setNum(MAX_CHANNEL_VALUE / 4)); + + valueText = cs->channelValueText(reinterpret_cast(pixel), ALPHA_CHANNEL); + CHECK(valueText, QString().setNum(MIN_CHANNEL_VALUE)); + + valueText = cs->normalisedChannelValueText(reinterpret_cast(pixel), RED_CHANNEL); + CHECK(valueText, QString().setNum(static_cast(MAX_CHANNEL_VALUE) / MAX_CHANNEL_VALUE)); + + valueText = cs->normalisedChannelValueText(reinterpret_cast(pixel), GREEN_CHANNEL); + CHECK(valueText, QString().setNum(static_cast(MAX_CHANNEL_VALUE / 2) / MAX_CHANNEL_VALUE)); + + valueText = cs->normalisedChannelValueText(reinterpret_cast(pixel), BLUE_CHANNEL); + CHECK(valueText, QString().setNum(static_cast(MAX_CHANNEL_VALUE / 4) / MAX_CHANNEL_VALUE)); + + valueText = cs->normalisedChannelValueText(reinterpret_cast(pixel), ALPHA_CHANNEL); + CHECK(valueText, QString().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); + + Q_UINT16 red; + Q_UINT16 green; + Q_UINT16 blue; + Q_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. + Q_UINT16 pixel1[NUM_CHANNELS]; + Q_UINT16 pixel2[NUM_CHANNELS]; + Q_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 Q_UINT8 *pixelPtrs[2]; + Q_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::testToQImage() +{ + 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} + }; + + QImage image = cs->convertToQImage(reinterpret_cast(pixels), PIXELS_WIDTH, PIXELS_HEIGHT, 0, 0); + + QRgb c = image.pixel(0, 0); + + CHECK(qRed(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE)); + CHECK(qGreen(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE)); + CHECK(qBlue(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE)); + CHECK(qAlpha(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE / 4)); + + c = image.pixel(1, 0); + + CHECK(qRed(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE / 3)); + CHECK(qGreen(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE / 2)); + CHECK_TOLERANCE(qBlue(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE / 4), 1u); + CHECK(qAlpha(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE / 2)); + + c = image.pixel(0, 1); + + CHECK(qRed(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE)); + CHECK(qGreen(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE)); + CHECK(qBlue(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE)); + CHECK(qAlpha(c), (int)UINT16_TO_UINT8(MIN_CHANNEL_VALUE)); + + c = image.pixel(1, 1); + + CHECK(qRed(c), (int)UINT16_TO_UINT8(MIN_CHANNEL_VALUE)); + CHECK(qGreen(c), (int)UINT16_TO_UINT8(MIN_CHANNEL_VALUE)); + CHECK(qBlue(c), (int)UINT16_TO_UINT8(MIN_CHANNEL_VALUE)); + CHECK(qAlpha(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, (Q_UINT16)UINT8_TO_UINT16(253)); + CHECK(dstPixel.green, (Q_UINT16)UINT8_TO_UINT16(254)); + CHECK(dstPixel.blue, (Q_UINT16)UINT8_TO_UINT16(254)); + CHECK(dstPixel.alpha, KisRgbU16ColorSpace::U16_OPACITY_OPAQUE); + + Q_UINT16 srcColor = 43690; + Q_UINT16 dstColor = 43690; + + srcColor = QMIN((dstColor * (65535u + 1u) + (srcColor / 2u)) / (1u + srcColor), 65535u); + + CHECK((int)srcColor, 65534); + + Q_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, mask, MASK_ROW_STRIDE, NUM_ROWS, NUM_COLUMNS, opacity); + */ + + delete cs; +} + diff --git a/krita/colorspaces/rgb_u16/tests/kis_strategy_colorspace_rgb_u16_tester.h b/krita/colorspaces/rgb_u16/tests/kis_strategy_colorspace_rgb_u16_tester.h new file mode 100644 index 00000000..e80a7a43 --- /dev/null +++ b/krita/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(QString(__FILE__) + "[" + QString::number(__LINE__) + "]: passed " + #x); \ +} \ +else \ +{ \ + failure(QString(__FILE__) + "[" + QString::number(__LINE__) + QString("]: failed ") + #x + "\n Expected " + #y + ", Actual result " + QString::number(x)); \ +} \ + +class KisRgbU16ColorSpaceTester : public KUnitTest::Tester +{ +public: + void allTests(); + void testBasics(); + void testMixColors(); + void testToQImage(); + void testCompositeOps(); +}; + +#endif + diff --git a/krita/colorspaces/rgb_u8/Makefile.am b/krita/colorspaces/rgb_u8/Makefile.am new file mode 100644 index 00000000..4d8ab87c --- /dev/null +++ b/krita/colorspaces/rgb_u8/Makefile.am @@ -0,0 +1,33 @@ +# Install the desktop file needed to detect the plugin +kde_services_DATA = kritargbplugin.desktop + +INCLUDES = -I$(srcdir)/../../sdk \ + -I$(srcdir)/../../kritacolor/color_strategy/ \ + -I$(srcdir)/../../kritacolor/ \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +lib_LTLIBRARIES = libkritargb.la +libkritargb_la_SOURCES = kis_rgb_colorspace.cc +libkritargb_la_LDFLAGS = $(all_libraries) +libkritargb_la_LIBADD = ../../kritacolor/libkritacolor.la + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = kritargbplugin.la + +# Srcs for the plugin +kritargbplugin_la_SOURCES = rgb_plugin.cc +noinst_HEADERS = rgb_plugin.h kis_rgb_colorspace.h + +kritargbplugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritargbplugin_la_LIBADD = libkritargb.la ../../kritacolor/libkritacolor.la + +kritargbplugin_la_METASOURCES = AUTO +#METASOURCES = AUTO # XXX: which of the two? + +if include_kunittest_tests +TESTSDIR = tests +endif + +SUBDIRS = . templates $(TESTSDIR) + diff --git a/krita/colorspaces/rgb_u8/composite.h b/krita/colorspaces/rgb_u8/composite.h new file mode 100644 index 00000000..961130ba --- /dev/null +++ b/krita/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. + * Krita 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) ((Q_UINT8)PixelIntensity(pixel)) + +#define PixelIntensityToDouble(pixel) ((double)PixelIntensity(pixel)) + +#define RoundSignedToQuantum(value) ((Q_UINT8) (value < 0 ? 0 : \ + (value > Q_UINT8_MAX) ? Q_UINT8_MAX : value + 0.5)) + +#define RoundToQuantum(value) ((Q_UINT8) (value > Q_UINT8_MAX ? Q_UINT8_MAX : \ + value + 0.5)) + +// And from studio.h +#define AbsoluteValue(x) ((x) < 0 ? -(x) : (x)) + +void compositeIn(Q_INT32 pixelSize, + Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowSize, + Q_INT32 rows, + Q_INT32 cols, + Q_UINT8 opacity = OPACITY_OPAQUE) +{ + + if (opacity == OPACITY_TRANSPARENT) + return; + + Q_UINT8 *d; + const Q_UINT8 *s; + + Q_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(Q_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]=(Q_UINT8) (((double) UINT8_MAX - sAlpha) * + (UINT8_MAX-dAlpha) * s[PIXEL_RED] / UINT8_MAX / alpha + 0.5); + d[PIXEL_GREEN]=(Q_UINT8) (((double) UINT8_MAX - sAlpha)* + (UINT8_MAX-dAlpha) * s[PIXEL_GREEN] / UINT8_MAX / alpha + 0.5); + d[PIXEL_BLUE]=(Q_UINT8) (((double) UINT8_MAX - sAlpha)* + (UINT8_MAX - dAlpha) * s[PIXEL_BLUE] / UINT8_MAX / alpha + 0.5); + d[PIXEL_ALPHA]=(Q_UINT8) ((d[PIXEL_ALPHA] * (UINT8_MAX - alpha) / UINT8_MAX) + 0.5); + + } + dst += dstRowSize; + src += srcRowSize; + } + +} + +void compositeOut(Q_INT32 pixelSize, + Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowSize, + Q_INT32 rows, + Q_INT32 cols, + Q_UINT8 opacity = OPACITY_OPAQUE) +{ + if (opacity == OPACITY_TRANSPARENT) + return; + + Q_UINT8 *d; + const Q_UINT8 *s; + + Q_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(Q_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] = (Q_UINT8) (((double) UINT8_MAX - sAlpha) * dAlpha * s[PIXEL_RED] / UINT8_MAX / alpha + 0.5); + d[PIXEL_GREEN] = (Q_UINT8) (((double) UINT8_MAX - sAlpha) * dAlpha * s[PIXEL_GREEN] / UINT8_MAX / alpha + 0.5); + d[PIXEL_BLUE] = (Q_UINT8) (((double) UINT8_MAX - sAlpha) * dAlpha * s[PIXEL_BLUE] / UINT8_MAX / alpha + 0.5); + d[PIXEL_ALPHA]=(Q_UINT8) ((d[PIXEL_ALPHA] * (UINT8_MAX - alpha) / UINT8_MAX) + 0.5); + } + dst += dstRowSize; + src += srcRowSize; + } + +} + +void compositeAtop(Q_INT32 pixelSize, + Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowSize, + Q_INT32 rows, + Q_INT32 cols, + Q_UINT8 opacity = OPACITY_OPAQUE) +{ + + if (opacity == OPACITY_TRANSPARENT) + return; + + Q_UINT8 *d; + const Q_UINT8 *s; + + Q_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] = (Q_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] = (Q_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] = (Q_UINT8) (blue > UINT8_MAX ? UINT8_MAX : blue + 0.5); + d[PIXEL_ALPHA]=(Q_UINT8) (UINT8_MAX - (alpha > UINT8_MAX ? UINT8_MAX : alpha) + 0.5); + } + dst += dstRowSize; + src += srcRowSize; + } +} + + +void compositeXor(Q_INT32 pixelSize, + Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowSize, + Q_INT32 rows, + Q_INT32 cols, + Q_UINT8 opacity = OPACITY_OPAQUE) +{ + if (opacity == OPACITY_TRANSPARENT) + return; + + Q_UINT8 *d; + const Q_UINT8 *s; + + Q_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(Q_INT32 pixelSize, + Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowSize, + Q_INT32 rows, + Q_INT32 cols, + Q_UINT8 opacity = OPACITY_OPAQUE) +{ + if (opacity == OPACITY_TRANSPARENT) + return; + + Q_UINT8 *d; + const Q_UINT8 *s; + + Q_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(Q_INT32 pixelSize, + Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowSize, + Q_INT32 rows, + Q_INT32 cols, + Q_UINT8 opacity = OPACITY_OPAQUE) +{ + if (opacity == OPACITY_TRANSPARENT) + return; + + Q_UINT8 *d; + const Q_UINT8 *s; + + Q_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(Q_INT32 pixelSize, + Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowSize, + Q_INT32 rows, + Q_INT32 cols, + Q_UINT8 opacity = OPACITY_OPAQUE) +{ + if (opacity == OPACITY_TRANSPARENT) + return; + + Q_UINT8 *d; + const Q_UINT8 *s; + + Q_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]=(Q_UINT8) + (red > UINT8_MAX ? red-=UINT8_MAX : red+0.5); + green=(double) s[PIXEL_GREEN]+d[PIXEL_GREEN]; + d[PIXEL_GREEN]=(Q_UINT8) + (green > UINT8_MAX ? green-=UINT8_MAX : green+0.5); + blue=(double) s[PIXEL_BLUE]+d[PIXEL_BLUE]; + d[PIXEL_BLUE]=(Q_UINT8) + (blue > UINT8_MAX ? blue-=UINT8_MAX : blue+0.5); + d[PIXEL_ALPHA]=OPACITY_OPAQUE; + } + dst += dstRowSize; + src += srcRowSize; + } + +} + +void compositeSubtract(Q_INT32 pixelSize, + Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowSize, + Q_INT32 rows, + Q_INT32 cols, + Q_UINT8 opacity = OPACITY_OPAQUE) +{ + if (opacity == OPACITY_TRANSPARENT) + return; + + Q_UINT8 *d; + const Q_UINT8 *s; + + Q_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]=(Q_UINT8) + (red < 0 ? red+=UINT8_MAX : red+0.5); + green=(double) s[PIXEL_GREEN]-d[PIXEL_GREEN]; + d[PIXEL_GREEN]=(Q_UINT8) + (green < 0 ? green+=UINT8_MAX : green+0.5); + blue=(double) s[PIXEL_BLUE]-d[PIXEL_BLUE]; + d[PIXEL_BLUE]=(Q_UINT8) + (blue < 0 ? blue+=UINT8_MAX : blue+0.5); + d[PIXEL_ALPHA]=OPACITY_OPAQUE; + + } + dst += dstRowSize; + src += srcRowSize; + } + +} + +void compositeDiff(Q_INT32 pixelSize, + Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowSize, + Q_INT32 rows, + Q_INT32 cols, + Q_UINT8 opacity = OPACITY_OPAQUE) +{ + if (opacity == OPACITY_TRANSPARENT) + return; + + Q_UINT8 *d; + const Q_UINT8 *s; + + Q_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]=(Q_UINT8) + AbsoluteValue(s[PIXEL_RED]-(double) d[PIXEL_RED]); + d[PIXEL_GREEN]=(Q_UINT8) + AbsoluteValue(s[PIXEL_GREEN]-(double) d[PIXEL_GREEN]); + d[PIXEL_BLUE]=(Q_UINT8) + AbsoluteValue(s[PIXEL_BLUE]-(double) d[PIXEL_BLUE]); + d[PIXEL_ALPHA]=UINT8_MAX - (Q_UINT8) + AbsoluteValue(sAlpha-(double) dAlpha); + + } + dst += dstRowSize; + src += srcRowSize; + } + +} + +void compositeBumpmap(Q_INT32 pixelSize, + Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowSize, + Q_INT32 rows, + Q_INT32 cols, + Q_UINT8 opacity = OPACITY_OPAQUE) +{ + if (opacity == OPACITY_TRANSPARENT) + return; + + Q_UINT8 *d; + const Q_UINT8 *s; + + Q_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]=(Q_UINT8) (((double) + intensity * d[PIXEL_RED])/UINT8_MAX +0.5); + d[PIXEL_GREEN]=(Q_UINT8) (((double) + intensity * d[PIXEL_GREEN])/UINT8_MAX +0.5); + d[PIXEL_BLUE]=(Q_UINT8) (((double) + intensity * d[PIXEL_BLUE])/UINT8_MAX +0.5); + d[PIXEL_ALPHA]= (Q_UINT8) (((double) + intensity * d[PIXEL_ALPHA])/UINT8_MAX +0.5); + + + } + dst += dstRowSize; + src += srcRowSize; + } + +} + +void compositeCopy(Q_INT32 pixelSize, + Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowSize, + Q_INT32 rows, + Q_INT32 cols, + Q_UINT8 /*opacity*/ = OPACITY_OPAQUE) +{ + Q_UINT8 *d; + const Q_UINT8 *s; + d = dst; + s = src; + Q_UINT32 len = cols * pixelSize; + + while (rows-- > 0) { + memcpy(d, s, len); + d += dstRowSize; + s += srcRowSize; + } +} + +void compositeCopyChannel(Q_UINT8 pixel, + Q_INT32 pixelSize, + Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowSize, + Q_INT32 rows, + Q_INT32 cols, + Q_UINT8 /*opacity*/ = OPACITY_OPAQUE) +{ + Q_UINT8 *d; + const Q_UINT8 *s; + Q_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(Q_INT32 pixelSize, + Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowSize, + Q_INT32 rows, + Q_INT32 cols, + Q_UINT8 opacity = OPACITY_OPAQUE) +{ + compositeCopyChannel(PIXEL_RED, pixelSize, dst, dstRowSize, src, srcRowSize, rows, cols, opacity); +} + +void compositeCopyGreen(Q_INT32 pixelSize, + Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowSize, + Q_INT32 rows, + Q_INT32 cols, + Q_UINT8 opacity = OPACITY_OPAQUE) +{ + compositeCopyChannel(PIXEL_GREEN, pixelSize, dst, dstRowSize, src, srcRowSize, rows, cols, opacity); +} + +void compositeCopyBlue(Q_INT32 pixelSize, + Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowSize, + Q_INT32 rows, + Q_INT32 cols, + Q_UINT8 opacity = OPACITY_OPAQUE) +{ + compositeCopyChannel(PIXEL_BLUE, pixelSize, dst, dstRowSize, src, srcRowSize, rows, cols, opacity); +} + + +void compositeCopyOpacity(Q_INT32 pixelSize, + Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowSize, + Q_INT32 rows, + Q_INT32 cols, + Q_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(Q_INT32 pixelSize, + Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 /*srcRowSize*/, + Q_INT32 rows, + Q_INT32 cols, + Q_UINT8 /*opacity*/ = OPACITY_OPAQUE) +{ + + Q_INT32 linesize = pixelSize * sizeof(Q_UINT8) * cols; + Q_UINT8 *d; + const Q_UINT8 *s; + + d = dst; + s = src; + + while (rows-- > 0) { + memset(d, 0, linesize); + d += dstRowSize; + } + +} + + +void compositeDissolve(Q_INT32 pixelSize, + Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowSize, + Q_INT32 rows, + Q_INT32 cols, + Q_UINT8 opacity = OPACITY_OPAQUE) +{ + if (opacity == OPACITY_TRANSPARENT) + return; + + Q_UINT8 *d; + const Q_UINT8 *s; + + Q_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]=(Q_UINT8) (((double) sAlpha*s[PIXEL_RED]+ + (UINT8_MAX -sAlpha)*d[PIXEL_RED])/UINT8_MAX +0.5); + d[PIXEL_GREEN]= (Q_UINT8) (((double) sAlpha*s[PIXEL_GREEN]+ + (UINT8_MAX -sAlpha)*d[PIXEL_GREEN])/UINT8_MAX +0.5); + d[PIXEL_BLUE] = (Q_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(Q_INT32 pixelSize, + Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowSize, + Q_INT32 rows, + Q_INT32 cols, + Q_UINT8 /*opacity*/ = OPACITY_OPAQUE) +{ + Q_INT32 linesize = pixelSize * sizeof(Q_UINT8) * cols; + Q_UINT8 *d; + const Q_UINT8 *s; + d = dst; + s = src; + + while (rows-- > 0) { + memcpy(d, s, linesize); + d += dstRowSize; + s += srcRowSize; + } + +} + +#if 0 +void compositeModulate(Q_INT32 pixelSize, + Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowSize, + Q_INT32 rows, + Q_INT32 cols, + Q_UINT8 opacity = OPACITY_OPAQUE) +{ + if (opacity == OPACITY_TRANSPARENT) + return; + + Q_UINT8 *d; + const Q_UINT8 *s; + + Q_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(Q_INT32 pixelSize, + Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowSize, + Q_INT32 rows, + Q_INT32 cols, + Q_UINT8 opacity = OPACITY_OPAQUE) +{ + Q_INT32 linesize = pixelSize * sizeof(Q_UINT8) * cols; + Q_UINT8 *d; + const Q_UINT8 *s; + Q_UINT8 alpha; + Q_UINT8 invAlpha; + Q_INT32 i; + +} + +#endif + +void compositeColorize(Q_INT32, + Q_UINT8 *, + Q_INT32 , + const Q_UINT8 *, + Q_INT32 , + Q_INT32 , + Q_INT32 , + Q_UINT8 ) +{ +} + + +void compositeLuminize(Q_INT32 , + Q_UINT8 *, + Q_INT32 , + const Q_UINT8 *, + Q_INT32 , + Q_INT32 , + Q_INT32 , + Q_UINT8 ) +{ + +} + +#endif + diff --git a/krita/colorspaces/rgb_u8/kis_rgb_colorspace.cc b/krita/colorspaces/rgb_u8/kis_rgb_colorspace.cc new file mode 100644 index 00000000..61272e36 --- /dev/null +++ b/krita/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) // ((Q_UINT8) (257UL*(value))) + +namespace { + const Q_INT32 MAX_CHANNEL_RGB = 3; + const Q_INT32 MAX_CHANNEL_RGBA = 4; +} + +KisRgbColorSpace::KisRgbColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) : + KisU8BaseColorSpace(KisID("RGBA", i18n("RGB (8-bit integer/channel)")), TYPE_BGRA_8, icSigRgbData, parent, p) +{ + m_channels.push_back(new KisChannelInfo(i18n("Red"), i18n("R"), 2, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, QColor(255,0,0))); + m_channels.push_back(new KisChannelInfo(i18n("Green"), i18n("G"), 1, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, QColor(0,255,0))); + m_channels.push_back(new KisChannelInfo(i18n("Blue"), i18n("B"), 0, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, QColor(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(Q_UINT8 *pixel, Q_UINT8 red, Q_UINT8 green, Q_UINT8 blue, Q_UINT8 alpha) const +{ + pixel[PIXEL_RED] = red; + pixel[PIXEL_GREEN] = green; + pixel[PIXEL_BLUE] = blue; + pixel[PIXEL_ALPHA] = alpha; +} + +void KisRgbColorSpace::getPixel(const Q_UINT8 *pixel, Q_UINT8 *red, Q_UINT8 *green, Q_UINT8 *blue, Q_UINT8 *alpha) const +{ + *red = pixel[PIXEL_RED]; + *green = pixel[PIXEL_GREEN]; + *blue = pixel[PIXEL_BLUE]; + *alpha = pixel[PIXEL_ALPHA]; +} + +void KisRgbColorSpace::mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const +{ + Q_UINT32 totalRed = 0, totalGreen = 0, totalBlue = 0, totalAlpha = 0; + + while (nColors--) + { + Q_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 + Q_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 + + Q_UINT32 dstRed = totalRed; + //Q_ASSERT(dstRed <= 255); + if (dstRed > 255) dstRed = 255; + dst[PIXEL_RED] = dstRed; + + Q_UINT32 dstGreen = totalGreen; + //Q_ASSERT(dstGreen <= 255); + if (dstGreen > 255) dstGreen = 255; + dst[PIXEL_GREEN] = dstGreen; + + Q_UINT32 dstBlue = totalBlue; + //Q_ASSERT(dstBlue <= 255); + if (dstBlue > 255) dstBlue = 255; + dst[PIXEL_BLUE] = dstBlue; +} + +void KisRgbColorSpace::convolveColors(Q_UINT8** colors, Q_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const +{ + Q_INT64 totalRed = 0, totalGreen = 0, totalBlue = 0, totalAlpha = 0; + Q_INT32 totalWeight = 0, totalWeightTransparent = 0; + while (nColors--) + { + Q_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, Q_UINT8_MAX); + dst[PIXEL_GREEN] = CLAMP((totalGreen / factor) + offset, 0, Q_UINT8_MAX); + dst[PIXEL_BLUE] = CLAMP((totalBlue / factor) + offset, 0, Q_UINT8_MAX); + } + if (channelFlags & KisChannelInfo::FLAG_ALPHA) { + dst[PIXEL_ALPHA] = CLAMP((totalAlpha/ factor) + offset, 0, Q_UINT8_MAX); + } + } else if(totalWeightTransparent != totalWeight && (channelFlags & KisChannelInfo::FLAG_COLOR)) { + if(totalWeight == factor) + { + Q_INT64 a = ( totalWeight - totalWeightTransparent ); + dst[PIXEL_RED] = CLAMP((totalRed / a) + offset, 0, Q_UINT8_MAX); + dst[PIXEL_GREEN] = CLAMP((totalGreen / a) + offset, 0, Q_UINT8_MAX); + dst[PIXEL_BLUE] = CLAMP((totalBlue / a) + offset, 0, Q_UINT8_MAX); + } else { + double a = totalWeight / ( factor * ( totalWeight - totalWeightTransparent ) ); // use double as it can saturate + dst[PIXEL_RED] = CLAMP( (Q_UINT8)(totalRed * a) + offset, 0, Q_UINT8_MAX); + dst[PIXEL_GREEN] = CLAMP( (Q_UINT8)(totalGreen * a) + offset, 0, Q_UINT8_MAX); + dst[PIXEL_BLUE] = CLAMP( (Q_UINT8)(totalBlue * a) + offset, 0, Q_UINT8_MAX); + } + } + if (channelFlags & KisChannelInfo::FLAG_ALPHA) { + dst[PIXEL_ALPHA] = CLAMP((totalAlpha/ factor) + offset, 0, Q_UINT8_MAX); + } +} + + +void KisRgbColorSpace::invertColor(Q_UINT8 * src, Q_INT32 nPixels) +{ + Q_UINT32 psize = pixelSize(); + + while (nPixels--) + { + src[PIXEL_RED] = Q_UINT8_MAX - src[PIXEL_RED]; + src[PIXEL_GREEN] = Q_UINT8_MAX - src[PIXEL_GREEN]; + src[PIXEL_BLUE] = Q_UINT8_MAX - src[PIXEL_BLUE]; + + src += psize; + } +} + + +void KisRgbColorSpace::darken(const Q_UINT8 * src, Q_UINT8 * dst, Q_INT32 shade, bool compensate, double compensation, Q_INT32 nPixels) const +{ + Q_UINT32 pSize = pixelSize(); + + while (nPixels--) { + if (compensate) { + dst[PIXEL_RED] = (Q_INT8) QMIN(255,((src[PIXEL_RED] * shade) / (compensation * 255))); + dst[PIXEL_GREEN] = (Q_INT8) QMIN(255,((src[PIXEL_GREEN] * shade) / (compensation * 255))); + dst[PIXEL_BLUE] = (Q_INT8) QMIN(255,((src[PIXEL_BLUE] * shade) / (compensation * 255))); + } + else { + dst[PIXEL_RED] = (Q_INT8) QMIN(255, (src[PIXEL_RED] * shade / 255)); + dst[PIXEL_BLUE] = (Q_INT8) QMIN(255, (src[PIXEL_BLUE] * shade / 255)); + dst[PIXEL_GREEN] = (Q_INT8) QMIN(255, (src[PIXEL_GREEN] * shade / 255)); + } + dst += pSize; + src += pSize; + } +} + +Q_UINT8 KisRgbColorSpace::intensity8(const Q_UINT8 * src) const +{ + return (Q_UINT8)((src[PIXEL_RED] * 0.30 + src[PIXEL_GREEN] * 0.59 + src[PIXEL_BLUE] * 0.11) + 0.5); +} + +QValueVector KisRgbColorSpace::channels() const +{ + return m_channels; +} + +Q_UINT32 KisRgbColorSpace::nChannels() const +{ + return MAX_CHANNEL_RGBA; +} + +Q_UINT32 KisRgbColorSpace::nColorChannels() const +{ + return MAX_CHANNEL_RGB; +} + +Q_UINT32 KisRgbColorSpace::pixelSize() const +{ + return MAX_CHANNEL_RGBA; +} + +QImage KisRgbColorSpace::convertToQImage(const Q_UINT8 *data, Q_INT32 width, Q_INT32 height, + KisProfile * dstProfile, + Q_INT32 renderingIntent, float /*exposure*/) + +{ + Q_ASSERT(data); + QImage img = QImage(const_cast(data), width, height, 32, 0, 0, QImage::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(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, + const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, + const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, + Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + while (rows > 0) { + + const Q_UINT8 *src = srcRowStart; + Q_UINT8 *dst = dstRowStart; + const Q_UINT8 *mask = maskRowStart; + Q_INT32 columns = numColumns; + + while (columns > 0) { + + Q_UINT8 srcAlpha = src[PIXEL_ALPHA]; + + // apply the alphamask + if(mask != 0) + { + if(*mask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *mask); + mask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(srcAlpha, opacity); + } + + if (srcAlpha == OPACITY_OPAQUE) { + memcpy(dst, src, MAX_CHANNEL_RGBA * sizeof(Q_UINT8)); + } else { + Q_UINT8 dstAlpha = dst[PIXEL_ALPHA]; + + Q_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + Q_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(Q_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(maskRowStart) + maskRowStart += maskRowStride; + } +} + + +void KisRgbColorSpace::compositeAlphaDarken(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, + const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, + const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, + Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + while (rows > 0) { + + const Q_UINT8 *src = srcRowStart; + Q_UINT8 *dst = dstRowStart; + const Q_UINT8 *mask = maskRowStart; + Q_INT32 columns = numColumns; + + while (columns > 0) { + + Q_UINT8 srcAlpha = src[PIXEL_ALPHA]; + Q_UINT8 dstAlpha = dst[PIXEL_ALPHA]; + + // apply the alphamask + if(mask != 0) + { + if(*mask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *mask); + mask++; + } + + 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(Q_UINT8)); + } + + columns--; + src += MAX_CHANNEL_RGBA; + dst += MAX_CHANNEL_RGBA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(maskRowStart) + maskRowStart += maskRowStride; + } +} + + +void KisRgbColorSpace::compositeMultiply(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + while (rows > 0) { + + const Q_UINT8 *src = srcRowStart; + Q_UINT8 *dst = dstRowStart; + Q_INT32 columns = numColumns; + const Q_UINT8 *mask = maskRowStart; + + while (columns > 0) { + + Q_UINT8 srcAlpha = src[PIXEL_ALPHA]; + Q_UINT8 dstAlpha = dst[PIXEL_ALPHA]; + + srcAlpha = QMIN(srcAlpha, dstAlpha); + + // apply the alphamask + if(mask != 0) + { + if(*mask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *mask); + mask++; + } + + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity); + } + + Q_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + Q_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha); + dst[PIXEL_ALPHA] = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + Q_UINT8 srcColor = src[PIXEL_RED]; + Q_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(maskRowStart) + maskRowStart += maskRowStride; + } +} + +void KisRgbColorSpace::compositeDivide(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + while (rows > 0) { + + const Q_UINT8 *src = srcRowStart; + Q_UINT8 *dst = dstRowStart; + Q_INT32 columns = numColumns; + const Q_UINT8 *mask = maskRowStart; + + while (columns > 0) { + + Q_UINT8 srcAlpha = src[PIXEL_ALPHA]; + Q_UINT8 dstAlpha = dst[PIXEL_ALPHA]; + + srcAlpha = QMIN(srcAlpha, dstAlpha); + + // apply the alphamask + if(mask != 0) + { + if(*mask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *mask); + mask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity); + } + + Q_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + Q_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++) { + + Q_UINT8 srcColor = src[channel]; + Q_UINT8 dstColor = dst[channel]; + + srcColor = QMIN((dstColor * (UINT8_MAX + 1u) + (srcColor / 2u)) / (1u + srcColor), UINT8_MAX); + + Q_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(maskRowStart) + maskRowStart += maskRowStride; + } +} + +void KisRgbColorSpace::compositeScreen(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + while (rows > 0) { + + const Q_UINT8 *src = srcRowStart; + Q_UINT8 *dst = dstRowStart; + Q_INT32 columns = numColumns; + const Q_UINT8 *mask = maskRowStart; + + while (columns > 0) { + + Q_UINT8 srcAlpha = src[PIXEL_ALPHA]; + Q_UINT8 dstAlpha = dst[PIXEL_ALPHA]; + + srcAlpha = QMIN(srcAlpha, dstAlpha); + + // apply the alphamask + if(mask != 0) + { + if(*mask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *mask); + mask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity); + } + + Q_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + Q_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++) { + + Q_UINT8 srcColor = src[channel]; + Q_UINT8 dstColor = dst[channel]; + + srcColor = UINT8_MAX - UINT8_MULT(UINT8_MAX - dstColor, UINT8_MAX - srcColor); + + Q_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(maskRowStart) + maskRowStart += maskRowStride; + } +} + +void KisRgbColorSpace::compositeOverlay(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + while (rows > 0) { + + const Q_UINT8 *src = srcRowStart; + Q_UINT8 *dst = dstRowStart; + Q_INT32 columns = numColumns; + const Q_UINT8 *mask = maskRowStart; + + while (columns > 0) { + + Q_UINT8 srcAlpha = src[PIXEL_ALPHA]; + Q_UINT8 dstAlpha = dst[PIXEL_ALPHA]; + + srcAlpha = QMIN(srcAlpha, dstAlpha); + + // apply the alphamask + if(mask != 0) + { + if(*mask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *mask); + mask++; + } + + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity); + } + + Q_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + Q_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++) { + + Q_UINT8 srcColor = src[channel]; + Q_UINT8 dstColor = dst[channel]; + + srcColor = UINT8_MULT(dstColor, dstColor + UINT8_MULT(2 * srcColor, UINT8_MAX - dstColor)); + + Q_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(maskRowStart) + maskRowStart += maskRowStride; + } +} + +void KisRgbColorSpace::compositeDodge(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + while (rows > 0) { + + const Q_UINT8 *src = srcRowStart; + Q_UINT8 *dst = dstRowStart; + Q_INT32 columns = numColumns; + const Q_UINT8 *mask = maskRowStart; + + while (columns > 0) { + + Q_UINT8 srcAlpha = src[PIXEL_ALPHA]; + Q_UINT8 dstAlpha = dst[PIXEL_ALPHA]; + + srcAlpha = QMIN(srcAlpha, dstAlpha); + + // apply the alphamask + if(mask != 0) + { + if(*mask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *mask); + mask++; + } + + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity); + } + + Q_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + Q_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++) { + + Q_UINT8 srcColor = src[channel]; + Q_UINT8 dstColor = dst[channel]; + + srcColor = QMIN((dstColor * (UINT8_MAX + 1)) / (UINT8_MAX + 1 - srcColor), UINT8_MAX); + + Q_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(maskRowStart) + maskRowStart += maskRowStride; + } +} + +void KisRgbColorSpace::compositeBurn(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + while (rows > 0) { + + const Q_UINT8 *src = srcRowStart; + Q_UINT8 *dst = dstRowStart; + Q_INT32 columns = numColumns; + const Q_UINT8 *mask = maskRowStart; + + while (columns > 0) { + + Q_UINT8 srcAlpha = src[PIXEL_ALPHA]; + Q_UINT8 dstAlpha = dst[PIXEL_ALPHA]; + + srcAlpha = QMIN(srcAlpha, dstAlpha); + + // apply the alphamask + if(mask != 0) + { + if(*mask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *mask); + mask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity); + } + + Q_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + Q_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++) { + + Q_UINT8 srcColor = src[channel]; + Q_UINT8 dstColor = dst[channel]; + + srcColor = QMIN(((UINT8_MAX - dstColor) * (UINT8_MAX + 1)) / (srcColor + 1), UINT8_MAX); + if (UINT8_MAX - srcColor > UINT8_MAX) srcColor = UINT8_MAX; + + Q_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(maskRowStart) + maskRowStart += maskRowStride; + } +} + +void KisRgbColorSpace::compositeDarken(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + while (rows > 0) { + + const Q_UINT8 *src = srcRowStart; + Q_UINT8 *dst = dstRowStart; + Q_INT32 columns = numColumns; + const Q_UINT8 *mask = maskRowStart; + + while (columns > 0) { + + Q_UINT8 srcAlpha = src[PIXEL_ALPHA]; + Q_UINT8 dstAlpha = dst[PIXEL_ALPHA]; + + srcAlpha = QMIN(srcAlpha, dstAlpha); + + // apply the alphamask + if(mask != 0) + { + if(*mask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *mask); + mask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity); + } + + Q_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + Q_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++) { + + Q_UINT8 srcColor = src[channel]; + Q_UINT8 dstColor = dst[channel]; + + srcColor = QMIN(srcColor, dstColor); + + Q_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(maskRowStart) + maskRowStart += maskRowStride; + } +} + +void KisRgbColorSpace::compositeLighten(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + while (rows > 0) { + + const Q_UINT8 *src = srcRowStart; + Q_UINT8 *dst = dstRowStart; + Q_INT32 columns = numColumns; + const Q_UINT8 *mask = maskRowStart; + + while (columns > 0) { + + Q_UINT8 srcAlpha = src[PIXEL_ALPHA]; + Q_UINT8 dstAlpha = dst[PIXEL_ALPHA]; + + srcAlpha = QMIN(srcAlpha, dstAlpha); + + // apply the alphamask + if(mask != 0) + { + if(*mask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *mask); + mask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity); + } + + Q_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + Q_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++) { + + Q_UINT8 srcColor = src[channel]; + Q_UINT8 dstColor = dst[channel]; + + srcColor = QMAX(srcColor, dstColor); + + Q_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(maskRowStart) + maskRowStart += maskRowStride; + } +} + +void KisRgbColorSpace::compositeHue(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + while (rows > 0) { + + const Q_UINT8 *src = srcRowStart; + Q_UINT8 *dst = dstRowStart; + Q_INT32 columns = numColumns; + const Q_UINT8 *mask = maskRowStart; + + while (columns > 0) { + + Q_UINT8 srcAlpha = src[PIXEL_ALPHA]; + Q_UINT8 dstAlpha = dst[PIXEL_ALPHA]; + + srcAlpha = QMIN(srcAlpha, dstAlpha); + + // apply the alphamask + if(mask != 0) + { + if(*mask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *mask); + mask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity); + } + + Q_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + Q_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(maskRowStart) + maskRowStart += maskRowStride; + } +} + +void KisRgbColorSpace::compositeSaturation(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + while (rows > 0) { + + const Q_UINT8 *src = srcRowStart; + Q_UINT8 *dst = dstRowStart; + Q_INT32 columns = numColumns; + const Q_UINT8 *mask = maskRowStart; + + while (columns > 0) { + + Q_UINT8 srcAlpha = src[PIXEL_ALPHA]; + Q_UINT8 dstAlpha = dst[PIXEL_ALPHA]; + + srcAlpha = QMIN(srcAlpha, dstAlpha); + + // apply the alphamask + if(mask != 0) + { + if(*mask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *mask); + mask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity); + } + + Q_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + Q_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(maskRowStart) + maskRowStart += maskRowStride; + } +} + +void KisRgbColorSpace::compositeValue(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + while (rows > 0) { + + const Q_UINT8 *src = srcRowStart; + Q_UINT8 *dst = dstRowStart; + Q_INT32 columns = numColumns; + const Q_UINT8 *mask = maskRowStart; + + while (columns > 0) { + + Q_UINT8 srcAlpha = src[PIXEL_ALPHA]; + Q_UINT8 dstAlpha = dst[PIXEL_ALPHA]; + + srcAlpha = QMIN(srcAlpha, dstAlpha); + + // apply the alphamask + if(mask != 0) + { + if(*mask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *mask); + mask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity); + } + + Q_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + Q_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(maskRowStart) + maskRowStart += maskRowStride; + } +} + +void KisRgbColorSpace::compositeColor(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + while (rows > 0) { + + const Q_UINT8 *src = srcRowStart; + Q_UINT8 *dst = dstRowStart; + Q_INT32 columns = numColumns; + const Q_UINT8 *mask = maskRowStart; + + while (columns > 0) { + + Q_UINT8 srcAlpha = src[PIXEL_ALPHA]; + Q_UINT8 dstAlpha = dst[PIXEL_ALPHA]; + + srcAlpha = QMIN(srcAlpha, dstAlpha); + + // apply the alphamask + if(mask != 0) + { + if(*mask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *mask); + mask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity); + } + + Q_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + Q_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); + + Q_UINT8 srcRed; + Q_UINT8 srcGreen; + Q_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(maskRowStart) + maskRowStart += maskRowStride; + } +} + +void KisRgbColorSpace::compositeErase(Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowSize, + const Q_UINT8 *srcAlphaMask, + Q_INT32 maskRowStride, + Q_INT32 rows, + Q_INT32 cols, + Q_UINT8 /*opacity*/) +{ + Q_INT32 i; + Q_UINT8 srcAlpha; + + while (rows-- > 0) + { + const Q_UINT8 *s = src; + Q_UINT8 *d = dst; + const Q_UINT8 *mask = srcAlphaMask; + + for (i = cols; i > 0; i--, s+=MAX_CHANNEL_RGBA, d+=MAX_CHANNEL_RGBA) + { + srcAlpha = s[PIXEL_ALPHA]; + // apply the alphamask + if(mask != 0) + { + if(*mask != OPACITY_OPAQUE) + srcAlpha = UINT8_BLEND(srcAlpha, OPACITY_OPAQUE, *mask); + mask++; + } + d[PIXEL_ALPHA] = UINT8_MULT(srcAlpha, d[PIXEL_ALPHA]); + } + + dst += dstRowSize; + if(srcAlphaMask) + srcAlphaMask += maskRowStride; + src += srcRowSize; + } +} + +void KisRgbColorSpace::bitBlt(Q_UINT8 *dst, + Q_INT32 dstRowStride, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 *mask, + Q_INT32 maskRowStride, + Q_UINT8 opacity, + Q_INT32 rows, + Q_INT32 cols, + const KisCompositeOp& op) +{ + + switch (op.op()) { + case COMPOSITE_UNDEF: + // Undefined == no composition + break; + case COMPOSITE_OVER: + compositeOver(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ALPHA_DARKEN: + compositeAlphaDarken(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DIVIDE: + compositeDivide(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_LIGHTEN: + compositeLighten(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_HUE: + compositeHue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_SATURATION: + compositeSaturation(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_VALUE: + compositeValue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COLOR: + compositeColor(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_OVERLAY: + compositeOverlay(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ERASE: + compositeErase(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DODGE: + compositeDodge(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_BURN: + compositeBurn(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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/krita/colorspaces/rgb_u8/kis_rgb_colorspace.h b/krita/colorspaces/rgb_u8/kis_rgb_colorspace.h new file mode 100644 index 00000000..40718251 --- /dev/null +++ b/krita/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 Q_UINT8 PIXEL_BLUE = 0; +const Q_UINT8 PIXEL_GREEN = 1; +const Q_UINT8 PIXEL_RED = 2; +const Q_UINT8 PIXEL_ALPHA = 3; + +class KRITATOOL_EXPORT KisRgbColorSpace : public KisU8BaseColorSpace { +public: + KisRgbColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p); + virtual ~KisRgbColorSpace(); + + virtual bool willDegrade(ColorSpaceIndependence) + { + return false; + }; + + +public: + void setPixel(Q_UINT8 *pixel, Q_UINT8 red, Q_UINT8 green, Q_UINT8 blue, Q_UINT8 alpha) const; + void getPixel(const Q_UINT8 *pixel, Q_UINT8 *red, Q_UINT8 *green, Q_UINT8 *blue, Q_UINT8 *alpha) const; + + virtual void mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const; + virtual void convolveColors(Q_UINT8** colors, Q_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const; + virtual void invertColor(Q_UINT8 * src, Q_INT32 nPixels); + virtual void darken(const Q_UINT8 * src, Q_UINT8 * dst, Q_INT32 shade, bool compensate, double compensation, Q_INT32 nPixels) const; + virtual Q_UINT8 intensity8(const Q_UINT8 * src) const; + + virtual QValueVector channels() const; + virtual Q_UINT32 nChannels() const; + virtual Q_UINT32 nColorChannels() const; + virtual Q_UINT32 pixelSize() const; + + virtual QImage convertToQImage(const Q_UINT8 *data, Q_INT32 width, Q_INT32 height, + KisProfile * dstProfile = 0, + Q_INT32 renderingIntent = INTENT_PERCEPTUAL, + float exposure = 0.0f); + + virtual KisCompositeOpList userVisiblecompositeOps() const; + +protected: + + virtual void bitBlt(Q_UINT8 *dst, + Q_INT32 dstRowStride, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 *srcAlphaMask, + Q_INT32 maskRowStride, + Q_UINT8 opacity, + Q_INT32 rows, + Q_INT32 cols, + const KisCompositeOp& op); + + void compositeOver(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeAlphaDarken(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeMultiply(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeDivide(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeScreen(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeOverlay(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeDodge(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeBurn(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeDarken(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeLighten(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeHue(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeSaturation(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeValue(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeColor(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeErase(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); +}; + +class KisRgbColorSpaceFactory : public KisColorSpaceFactory +{ +public: + /** + * Krita 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 Q_UINT32 colorSpaceType() { return TYPE_BGRA_8; }; + + virtual icColorSpaceSignature colorSpaceSignature() { return icSigRgbData; }; + + virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile * p) { return new KisRgbColorSpace(parent, p); }; + + virtual QString defaultProfile() { return "sRGB built-in - (lcms internal)"; }; +}; + +#endif // KIS_STRATEGY_COLORSPACE_RGB_H_ diff --git a/krita/colorspaces/rgb_u8/kritargbplugin.desktop b/krita/colorspaces/rgb_u8/kritargbplugin.desktop new file mode 100644 index 00000000..a8f5c30d --- /dev/null +++ b/krita/colorspaces/rgb_u8/kritargbplugin.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=Krita/ColorSpace +Type=Service +X-KDE-Library=kritargbplugin +X-Krita-Version=2 diff --git a/krita/colorspaces/rgb_u8/rgb_plugin.cc b/krita/colorspaces/rgb_u8/rgb_plugin.cc new file mode 100644 index 00000000..018c1491 --- /dev/null +++ b/krita/colorspaces/rgb_u8/rgb_plugin.cc @@ -0,0 +1,74 @@ +/* +* rgb_plugin.cc -- Part of Krita +* +* 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( kritargbplugin, RGBPluginFactory( "krita" ) ) + + +RGBPlugin::RGBPlugin(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(RGBPluginFactory::instance()); + + if ( parent->inherits("KisColorSpaceFactoryRegistry") ) + { + KisColorSpaceFactoryRegistry * f = dynamic_cast(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 + (KisID("RGB8HISTO", i18n("RGB8")), colorSpaceRGBA) ); + } + +} + +RGBPlugin::~RGBPlugin() +{ +} + +#include "rgb_plugin.moc" diff --git a/krita/colorspaces/rgb_u8/rgb_plugin.h b/krita/colorspaces/rgb_u8/rgb_plugin.h new file mode 100644 index 00000000..262d0bb4 --- /dev/null +++ b/krita/colorspaces/rgb_u8/rgb_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_PLUGIN_H_ +#define RGB_PLUGIN_H_ + +#include + +/** + * A plugin wrapper around the RGB colour space strategy. + */ +class RGBPlugin : public KParts::Plugin +{ + Q_OBJECT +public: + RGBPlugin(QObject *parent, const char *name, const QStringList &); + virtual ~RGBPlugin(); + +}; + + +#endif // RGB_PLUGIN_H_ diff --git a/krita/colorspaces/rgb_u8/rgbplugin.rc b/krita/colorspaces/rgb_u8/rgbplugin.rc new file mode 100644 index 00000000..cc618164 --- /dev/null +++ b/krita/colorspaces/rgb_u8/rgbplugin.rc @@ -0,0 +1,9 @@ + + +&Image + &Mode + + + + + diff --git a/krita/colorspaces/rgb_u8/templates/.directory b/krita/colorspaces/rgb_u8/templates/.directory new file mode 100644 index 00000000..4b475643 --- /dev/null +++ b/krita/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/krita/colorspaces/rgb_u8/templates/Makefile.am b/krita/colorspaces/rgb_u8/templates/Makefile.am new file mode 100644 index 00000000..29c87939 --- /dev/null +++ b/krita/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)/krita/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)/krita/templates/rgb/.source + +templatesicon_ICON = AUTO +templatesicondir = $(kde_datadir)/krita/icons diff --git a/krita/colorspaces/rgb_u8/templates/cr48-action-template_rgb_empty.png b/krita/colorspaces/rgb_u8/templates/cr48-action-template_rgb_empty.png new file mode 100644 index 00000000..ec4d6ddc Binary files /dev/null and b/krita/colorspaces/rgb_u8/templates/cr48-action-template_rgb_empty.png differ diff --git a/krita/colorspaces/rgb_u8/templates/crsc-action-template_rgb_empty.svgz b/krita/colorspaces/rgb_u8/templates/crsc-action-template_rgb_empty.svgz new file mode 100644 index 00000000..3ea7b854 Binary files /dev/null and b/krita/colorspaces/rgb_u8/templates/crsc-action-template_rgb_empty.svgz differ diff --git a/krita/colorspaces/rgb_u8/templates/transparent_1024x768.desktop b/krita/colorspaces/rgb_u8/templates/transparent_1024x768.desktop new file mode 100644 index 00000000..d22ad3e3 --- /dev/null +++ b/krita/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-Krita-Version=2 diff --git a/krita/colorspaces/rgb_u8/templates/transparent_1024x768.kra b/krita/colorspaces/rgb_u8/templates/transparent_1024x768.kra new file mode 100644 index 00000000..eb026588 Binary files /dev/null and b/krita/colorspaces/rgb_u8/templates/transparent_1024x768.kra differ diff --git a/krita/colorspaces/rgb_u8/templates/transparent_1280x1024.desktop b/krita/colorspaces/rgb_u8/templates/transparent_1280x1024.desktop new file mode 100644 index 00000000..58469cc6 --- /dev/null +++ b/krita/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-Krita-Version=2 diff --git a/krita/colorspaces/rgb_u8/templates/transparent_1280x1024.kra b/krita/colorspaces/rgb_u8/templates/transparent_1280x1024.kra new file mode 100644 index 00000000..be96fb23 Binary files /dev/null and b/krita/colorspaces/rgb_u8/templates/transparent_1280x1024.kra differ diff --git a/krita/colorspaces/rgb_u8/templates/transparent_1600x1200.desktop b/krita/colorspaces/rgb_u8/templates/transparent_1600x1200.desktop new file mode 100644 index 00000000..c4937805 --- /dev/null +++ b/krita/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-Krita-Version=2 diff --git a/krita/colorspaces/rgb_u8/templates/transparent_1600x1200.kra b/krita/colorspaces/rgb_u8/templates/transparent_1600x1200.kra new file mode 100644 index 00000000..b01685a9 Binary files /dev/null and b/krita/colorspaces/rgb_u8/templates/transparent_1600x1200.kra differ diff --git a/krita/colorspaces/rgb_u8/templates/transparent_640x480.desktop b/krita/colorspaces/rgb_u8/templates/transparent_640x480.desktop new file mode 100644 index 00000000..7dec238a --- /dev/null +++ b/krita/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-Krita-Version=2 diff --git a/krita/colorspaces/rgb_u8/templates/transparent_640x480.kra b/krita/colorspaces/rgb_u8/templates/transparent_640x480.kra new file mode 100644 index 00000000..59777c92 Binary files /dev/null and b/krita/colorspaces/rgb_u8/templates/transparent_640x480.kra differ diff --git a/krita/colorspaces/rgb_u8/templates/white_1024x768.desktop b/krita/colorspaces/rgb_u8/templates/white_1024x768.desktop new file mode 100644 index 00000000..57f097bf --- /dev/null +++ b/krita/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-Krita-Version=2 diff --git a/krita/colorspaces/rgb_u8/templates/white_1024x768.kra b/krita/colorspaces/rgb_u8/templates/white_1024x768.kra new file mode 100644 index 00000000..0a7702ad Binary files /dev/null and b/krita/colorspaces/rgb_u8/templates/white_1024x768.kra differ diff --git a/krita/colorspaces/rgb_u8/templates/white_1280x1024.desktop b/krita/colorspaces/rgb_u8/templates/white_1280x1024.desktop new file mode 100644 index 00000000..a6363424 --- /dev/null +++ b/krita/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-Krita-Version=2 diff --git a/krita/colorspaces/rgb_u8/templates/white_1280x1024.kra b/krita/colorspaces/rgb_u8/templates/white_1280x1024.kra new file mode 100644 index 00000000..8d552419 Binary files /dev/null and b/krita/colorspaces/rgb_u8/templates/white_1280x1024.kra differ diff --git a/krita/colorspaces/rgb_u8/templates/white_1600x1200.desktop b/krita/colorspaces/rgb_u8/templates/white_1600x1200.desktop new file mode 100644 index 00000000..bb43573f --- /dev/null +++ b/krita/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-Krita-Version=2 diff --git a/krita/colorspaces/rgb_u8/templates/white_1600x1200.kra b/krita/colorspaces/rgb_u8/templates/white_1600x1200.kra new file mode 100644 index 00000000..7c037d9e Binary files /dev/null and b/krita/colorspaces/rgb_u8/templates/white_1600x1200.kra differ diff --git a/krita/colorspaces/rgb_u8/templates/white_640x480.desktop b/krita/colorspaces/rgb_u8/templates/white_640x480.desktop new file mode 100644 index 00000000..2babefbf --- /dev/null +++ b/krita/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-Krita-Version=2 diff --git a/krita/colorspaces/rgb_u8/templates/white_640x480.kra b/krita/colorspaces/rgb_u8/templates/white_640x480.kra new file mode 100644 index 00000000..2a0265d0 Binary files /dev/null and b/krita/colorspaces/rgb_u8/templates/white_640x480.kra differ diff --git a/krita/colorspaces/rgb_u8/tests/Makefile.am b/krita/colorspaces/rgb_u8/tests/Makefile.am new file mode 100644 index 00000000..65832896 --- /dev/null +++ b/krita/colorspaces/rgb_u8/tests/Makefile.am @@ -0,0 +1,17 @@ +AM_CPPFLAGS = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/.. \ + -I$(srcdir)/../../../kritacolor/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 ../libkritargb.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/krita/colorspaces/rgb_u8/tests/kis_strategy_colorspace_rgb_tester.cpp b/krita/colorspaces/rgb_u8/tests/kis_strategy_colorspace_rgb_tester.cpp new file mode 100644 index 00000000..7ad4cfae --- /dev/null +++ b/krita/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); + + Q_UINT8 pixel[NUM_CHANNELS]; + + pixel[PIXEL_RED] = 255; + pixel[PIXEL_GREEN] = 128; + pixel[PIXEL_BLUE] = 64; + pixel[PIXEL_ALPHA] = 0; + + QString valueText = cs->channelValueText(pixel, RED_CHANNEL); + CHECK(valueText, QString("255")); + + valueText = cs->channelValueText(pixel, GREEN_CHANNEL); + CHECK(valueText, QString("128")); + + valueText = cs->channelValueText(pixel, BLUE_CHANNEL); + CHECK(valueText, QString("64")); + + valueText = cs->channelValueText(pixel, ALPHA_CHANNEL); + CHECK(valueText, QString("0")); + + valueText = cs->normalisedChannelValueText(pixel, RED_CHANNEL); + CHECK(valueText, QString().setNum(1.0)); + + valueText = cs->normalisedChannelValueText(pixel, GREEN_CHANNEL); + CHECK(valueText, QString().setNum(128.0 / 255.0)); + + valueText = cs->normalisedChannelValueText(pixel, BLUE_CHANNEL); + CHECK(valueText, QString().setNum(64.0 / 255.0)); + + valueText = cs->normalisedChannelValueText(pixel, ALPHA_CHANNEL); + CHECK(valueText, QString().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); + + Q_UINT8 red; + Q_UINT8 green; + Q_UINT8 blue; + Q_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. + Q_UINT8 pixel1[4]; + Q_UINT8 pixel2[4]; + Q_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 Q_UINT8 *pixelPtrs[2]; + Q_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/krita/colorspaces/rgb_u8/tests/kis_strategy_colorspace_rgb_tester.h b/krita/colorspaces/rgb_u8/tests/kis_strategy_colorspace_rgb_tester.h new file mode 100644 index 00000000..16fc4e83 --- /dev/null +++ b/krita/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/krita/colorspaces/wet/Makefile.am b/krita/colorspaces/wet/Makefile.am new file mode 100644 index 00000000..aaf561b0 --- /dev/null +++ b/krita/colorspaces/wet/Makefile.am @@ -0,0 +1,27 @@ +kritarcdir = $(kde_datadir)/kritaplugins +kritarc_DATA = wetplugin.rc +kde_services_DATA = kritawetplugin.desktop + +EXTRA_DIST = $(kritarc_DATA) + +INCLUDES = -I$(srcdir)/../../sdk \ + -I$(srcdir)/../../core \ + -I$(srcdir)/../../kritacolor/color_strategy/ \ + -I$(srcdir)/../../kritacolor/ \ + -I$(srcdir)/../../ui \ + -I$(srcdir)/../../kopalette \ + $(KOFFICE_INCLUDES) \ + -I$(interfacedir) \ + $(KOPAINTER_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = kritawetplugin.la + +kritawetplugin_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 + +kritawetplugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritawetplugin_la_LIBADD = ../../libkritacommon.la $(LIB_KOPAINTER) $(LIB_KOFFICECORE) + +kritawetplugin_la_METASOURCES = AUTO + diff --git a/krita/colorspaces/wet/kis_texture_filter.cc b/krita/colorspaces/wet/kis_texture_filter.cc new file mode 100644 index 00000000..1fc2e4d3 --- /dev/null +++ b/krita/colorspaces/wet/kis_texture_filter.cc @@ -0,0 +1,43 @@ +/* + * kis_texture_filter.cc -- Part of Krita + * + * 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, Q_INT32 w, Q_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/krita/colorspaces/wet/kis_texture_filter.h b/krita/colorspaces/wet/kis_texture_filter.h new file mode 100644 index 00000000..fb2ef021 --- /dev/null +++ b/krita/colorspaces/wet/kis_texture_filter.h @@ -0,0 +1,38 @@ +/* + * kis_texture_filter.h -- Part of Krita + * + * 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, Q_INT32 w = 0, Q_INT32 h = 0) const; + virtual QString name() const { return i18n("Wet Texture"); } + virtual QString description() const { return i18n("Add a texture to the wet canvas"); } +}; + +#endif // _TEXTURE_FILTER_H diff --git a/krita/colorspaces/wet/kis_texture_painter.cc b/krita/colorspaces/wet/kis_texture_painter.cc new file mode 100644 index 00000000..a98038e6 --- /dev/null +++ b/krita/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( Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_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 = ( Q_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; + } + } + + // 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/krita/colorspaces/wet/kis_texture_painter.h b/krita/colorspaces/wet/kis_texture_painter.h new file mode 100644 index 00000000..a3323492 --- /dev/null +++ b/krita/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( Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h); + +private: + double m_blurh, m_height; + +}; +#endif //KIS_TEXTURE_PAINTER_H_ diff --git a/krita/colorspaces/wet/kis_wet_colorspace.cc b/krita/colorspaces/wet/kis_wet_colorspace.cc new file mode 100644 index 00000000..4ca96eb5 --- /dev/null +++ b/krita/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; + QColor c(r,g, b); + c.getHsv(&h, &s, &v); + return h; +} + +KisWetColorSpace::KisWetColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) : + KisAbstractColorSpace(KisID("WET", i18n("Watercolors")), 0, icMaxEnumData, parent, 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 QColor'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::fromQColor(const QColor& c, Q_UINT8 *dst, KisProfile * /*profile*/) +{ + WetPack* p = reinterpret_cast(dst); + + int h = getH(c.red(), c.green(), c.blue()); + int delta = 256; + int key = 0; + QMap::Iterator it; + QMap::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 QCOlors from our paintbox to wetpaint paints. + if (m_conversionMap.contains(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::fromQColor(const QColor& c, Q_UINT8 /*opacity*/, Q_UINT8 *dst, KisProfile * /*profile*/) +{ + fromQColor(c, dst); +} + + Q_UINT8 KisWetColorSpace::getAlpha(const Q_UINT8 */*pixel*/) const +{ + return OPACITY_OPAQUE; +} + +void KisWetColorSpace::setAlpha( Q_UINT8 * /*pixels*/, Q_UINT8 /*alpha*/, Q_INT32 /*nPixels*/) const +{ +} + +void KisWetColorSpace::multiplyAlpha( Q_UINT8 * /*pixels*/, Q_UINT8 /*alpha*/, Q_INT32 /*nPixels*/) +{ +} + +void KisWetColorSpace::applyAlphaU8Mask( Q_UINT8 * /*pixels*/, Q_UINT8 * /*alpha*/, Q_INT32 /*nPixels*/) +{ +} + +void KisWetColorSpace::applyInverseAlphaU8Mask( Q_UINT8 * /*pixels*/, Q_UINT8 * /*alpha*/, Q_INT32 /*nPixels*/) +{ +} + + Q_UINT8 KisWetColorSpace::scaleToU8(const Q_UINT8 * /*srcPixel*/, Q_INT32 /*channelPos*/) +{ + return 0; +} + +Q_UINT16 KisWetColorSpace::scaleToU16(const Q_UINT8 * /*srcPixel*/, Q_INT32 /*channelPos*/) +{ + return 0; +} + + +void KisWetColorSpace::toQColor(const Q_UINT8 *src, QColor *c, KisProfile * /*profile*/) +{ + Q_UINT8 * rgb = new Q_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::toQColor(const Q_UINT8 *src, QColor *c, Q_UINT8 */*opacity*/, KisProfile * /*profile*/) +{ + toQColor(src, c); +} + +void KisWetColorSpace::mixColors(const Q_UINT8 **/*colors*/, const Q_UINT8 */*weights*/, Q_UINT32 /*nColors*/, Q_UINT8 */*dst*/) const +{ +} + +QValueVector KisWetColorSpace::channels() const +{ + return m_channels; +} + + Q_UINT32 KisWetColorSpace::nChannels() const +{ + return 16; +} + + Q_UINT32 KisWetColorSpace::nColorChannels() const +{ + return 12; +} + + Q_UINT32 KisWetColorSpace::nSubstanceChannels() const +{ + return 4; +} + + + Q_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. +QImage KisWetColorSpace::convertToQImage(const Q_UINT8 *data, Q_INT32 width, Q_INT32 height, + KisProfile * /*dstProfile*/, + Q_INT32 /*renderingIntent*/, float /*exposure*/) +{ + + QImage img(width, height, 32); + + Q_UINT8 *rgb = (Q_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 + + Q_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( Q_UINT32); // Because the QImage is 4 bytes deep. + + } + + return img; +} + +void KisWetColorSpace::bitBlt( Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 */*srcAlphaMask*/, + Q_INT32 /*maskRowStride*/, + Q_UINT8 /*opacity*/, + Q_INT32 rows, + Q_INT32 cols, + const KisCompositeOp& op) +{ + if (rows <= 0 || cols <= 0) + return; + + Q_UINT8 *d; + const Q_UINT8 *s; + + Q_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 Q_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, Q_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( Q_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; +} + +QString KisWetColorSpace::channelValueText(const Q_UINT8 *U8_pixel, Q_UINT32 channelIndex) const +{ + Q_ASSERT(channelIndex < nChannels()); + const Q_UINT16 *pixel = reinterpret_cast(U8_pixel); + Q_UINT32 channelPosition = m_channels[channelIndex]->pos(); + + return QString().setNum(pixel[channelPosition]); +} + +QString KisWetColorSpace::normalisedChannelValueText(const Q_UINT8 *U8_pixel, Q_UINT32 channelIndex) const +{ + Q_ASSERT(channelIndex < nChannels()); + const Q_UINT16 *pixel = reinterpret_cast(U8_pixel); + Q_UINT32 channelPosition = m_channels[channelIndex]->pos(); + + return QString().setNum(static_cast(pixel[channelPosition]) / UINT16_MAX); +} + +QValueList KisWetColorSpace::createBackgroundFilters() +{ + QValueList filterList; + KisFilter * f = new WetPhysicsFilter(); + filterList << f; + return filterList; +} diff --git a/krita/colorspaces/wet/kis_wet_colorspace.h b/krita/colorspaces/wet/kis_wet_colorspace.h new file mode 100644 index 00000000..9c66c52e --- /dev/null +++ b/krita/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 { + Q_UINT16 rd; /* Total red channel concentration */ + Q_UINT16 rw; /* Myth-red concentration */ + + Q_UINT16 gd; /* Total green channel concentration */ + Q_UINT16 gw; /* Myth-green concentration */ + + Q_UINT16 bd; /* Total blue channel concentration */ + Q_UINT16 bw; /* Myth-blue concentration */ + + Q_UINT16 w; /* Water volume */ + Q_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 * parent, 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 + // QColors are mapped to plain water... + virtual void fromQColor(const QColor& c, Q_UINT8 *dst, KisProfile * profile = 0); + virtual void fromQColor(const QColor& c, Q_UINT8 opacity, Q_UINT8 *dst, KisProfile * profile = 0); + + virtual void toQColor(const Q_UINT8 *src, QColor *c, KisProfile * profile = 0); + virtual void toQColor(const Q_UINT8 *src, QColor *c, Q_UINT8 *opacity, KisProfile * profile = 0); + + virtual Q_UINT8 getAlpha(const Q_UINT8 * pixel) const; + virtual void setAlpha( Q_UINT8 * pixels, Q_UINT8 alpha, Q_INT32 nPixels) const; + virtual void multiplyAlpha( Q_UINT8 * pixels, Q_UINT8 alpha, Q_INT32 nPixels); + + virtual void applyAlphaU8Mask( Q_UINT8 * pixels, Q_UINT8 * alpha, Q_INT32 nPixels); + virtual void applyInverseAlphaU8Mask( Q_UINT8 * pixels, Q_UINT8 * alpha, Q_INT32 nPixels); + + virtual Q_UINT8 scaleToU8(const Q_UINT8 * srcPixel, Q_INT32 channelPos); + virtual Q_UINT16 scaleToU16(const Q_UINT8 * srcPixel, Q_INT32 channelPos); + + virtual void mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const; + + virtual QValueVector channels() const; + virtual Q_UINT32 nChannels() const; + virtual Q_UINT32 nColorChannels() const; + virtual Q_UINT32 nSubstanceChannels() const; + virtual Q_UINT32 pixelSize() const; + + virtual QString channelValueText(const Q_UINT8 *pixel, Q_UINT32 channelIndex) const; + virtual QString normalisedChannelValueText(const Q_UINT8 *pixel, Q_UINT32 channelIndex) const; + + virtual QImage convertToQImage(const Q_UINT8 *data, Q_INT32 width, Q_INT32 height, + KisProfile * dstProfile, + Q_INT32 renderingIntent = INTENT_PERCEPTUAL, + float exposure = 0.0f); + + virtual QValueList 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( Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 *srcAlphaMask, + Q_INT32 maskRowStride, + Q_UINT8 opacity, + Q_INT32 rows, + Q_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, Q_UINT8 *rgb, WetPix * wet); + + void wet_render_wetness( Q_UINT8 * rgb, WetPack * pack); + +private: + Q_UINT32 * wet_render_tab; + + QStringList m_paintNames; + QMap m_conversionMap; + + bool m_paintwetness; + int phase, phasebig; + +}; + +class KisWetColorSpaceFactory : public KisColorSpaceFactory +{ +public: + /** + * Krita 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 Q_UINT32 colorSpaceType() { return 0; }; + + virtual icColorSpaceSignature colorSpaceSignature() { return icMaxEnumData; }; + + virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) { return new KisWetColorSpace(parent, p); }; + + virtual QString defaultProfile() { return ""; }; +}; + +#endif // KIS_STRATEGY_COLORSPACE_WET_H_ diff --git a/krita/colorspaces/wet/kis_wet_palette_widget.cc b/krita/colorspaces/wet/kis_wet_palette_widget.cc new file mode 100644 index 00000000..ae405f94 --- /dev/null +++ b/krita/colorspaces/wet/kis_wet_palette_widget.cc @@ -0,0 +1,245 @@ +/* + * This file is part of Krita + * + * 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(QWidget *parent, const char *name) : super(parent, name) +{ + m_subject = 0; + + QVBoxLayout * vl = new QVBoxLayout(this, 0, -1, "main layout"); + + QGridLayout * l = new QGridLayout(vl, 2, 8, 2, "color wells grid"); + + KisColorCup * b; + int WIDTH = 24; + int HEIGHT = 24; + + b = new KisColorCup(this); + b->setColor( QColor(240, 32, 160) ); + l->addWidget(b, 0, 0); + QToolTip::add(b, i18n("Quinacridone Rose")); + b->setFixedSize(WIDTH, HEIGHT); + connect(b, SIGNAL(changed(const QColor &)), SLOT(slotFGColorSelected(const QColor &))); + + b = new KisColorCup(this); + b->setColor(QColor(159, 88, 43)); + l->addWidget(b, 0, 1); + QToolTip::add(b,i18n("Indian Red")); + b->setFixedSize(WIDTH, HEIGHT); + connect(b, SIGNAL(changed(const QColor &)), SLOT(slotFGColorSelected(const QColor &))); + + b = new KisColorCup(this); + b->setColor( QColor(254, 220, 64) ); + l->addWidget(b, 0, 2); + QToolTip::add(b,i18n("Cadmium Yellow")); + b->setFixedSize(WIDTH, HEIGHT); + connect(b, SIGNAL(changed(const QColor &)), SLOT(slotFGColorSelected(const QColor &))); + + b = new KisColorCup(this); + b->setColor(QColor(36, 180, 32)); + l->addWidget(b, 0, 3); + QToolTip::add(b,i18n("Hookers Green")); + b->setFixedSize(WIDTH, HEIGHT); + connect(b, SIGNAL(changed(const QColor &)), SLOT(slotFGColorSelected(const QColor &))); + + b = new KisColorCup(this); + b->setColor(QColor(16, 185, 215)); + l->addWidget(b, 0, 4); + QToolTip::add(b,i18n("Cerulean Blue")); + b->setFixedSize(WIDTH, HEIGHT); + connect(b, SIGNAL(changed(const QColor &)), SLOT(slotFGColorSelected(const QColor &))); + + b = new KisColorCup(this); + b->setColor(QColor(96, 32, 8)); + l->addWidget(b, 0, 5); + QToolTip::add(b,i18n("Burnt Umber")); + b->setFixedSize(WIDTH, HEIGHT); + connect(b, SIGNAL(changed(const QColor &)), SLOT(slotFGColorSelected(const QColor &))); + + b = new KisColorCup(this); + b->setColor(QColor(254, 96, 8)); + l->addWidget(b, 0, 6); + QToolTip::add(b,i18n("Cadmium Red")); + b->setFixedSize(WIDTH, HEIGHT); + connect(b, SIGNAL(changed(const QColor &)), SLOT(slotFGColorSelected(const QColor &))); + + b = new KisColorCup(this); + b->setColor(QColor(255, 136, 8)); + l->addWidget(b, 0, 7); + QToolTip::add(b,i18n("Brilliant Orange")); + b->setFixedSize(WIDTH, HEIGHT); + connect(b, SIGNAL(changed(const QColor &)), SLOT(slotFGColorSelected(const QColor &))); + + b = new KisColorCup(this); + b->setColor(QColor(240, 199, 8)); + l->addWidget(b, 1, 0); + QToolTip::add(b,i18n("Hansa Yellow")); + b->setFixedSize(WIDTH, HEIGHT); + connect(b, SIGNAL(changed(const QColor &)), SLOT(slotFGColorSelected(const QColor &))); + + b = new KisColorCup(this); + b->setColor(QColor(96, 170, 130)); + l->addWidget(b, 1, 1); + QToolTip::add(b,i18n("Phthalo Green")); + b->setFixedSize(WIDTH, HEIGHT); + connect(b, SIGNAL(changed(const QColor &)), SLOT(slotFGColorSelected(const QColor &))); + + b = new KisColorCup(this); + b->setColor(QColor(48, 32, 170)); + l->addWidget(b, 1, 2); + QToolTip::add(b,i18n("French Ultramarine")); + b->setFixedSize(WIDTH, HEIGHT); + connect(b, SIGNAL(changed(const QColor &)), SLOT(slotFGColorSelected(const QColor &))); + + b = new KisColorCup(this); + b->setColor(QColor(118, 16, 135)); + l->addWidget(b, 1, 3); + QToolTip::add(b,i18n("Interference Lilac")); + b->setFixedSize(WIDTH, HEIGHT); + connect(b, SIGNAL(changed(const QColor &)), SLOT(slotFGColorSelected(const QColor &))); + + b = new KisColorCup(this); + b->setColor(QColor(254, 254, 254)); + l->addWidget(b, 1, 4); + QToolTip::add(b,i18n("Titanium White")); + b->setFixedSize(WIDTH, HEIGHT); + connect(b, SIGNAL(changed(const QColor &)), SLOT(slotFGColorSelected(const QColor &))); + + b = new KisColorCup(this); + b->setColor(QColor(64, 64, 74)); + l->addWidget(b, 1, 5); + QToolTip::add(b,i18n("Ivory Black")); + b->setFixedSize(WIDTH, HEIGHT); + connect(b, SIGNAL(changed(const QColor &)), SLOT(slotFGColorSelected(const QColor &))); + + b = new KisColorCup(this); + b->setColor(QColor(255, 255, 255)); + l->addWidget(b, 1, 6); + QToolTip::add(b,i18n("Pure Water")); + b->setFixedSize(WIDTH, HEIGHT); + connect(b, SIGNAL(changed(const QColor &)), SLOT(slotFGColorSelected(const QColor &))); + + QGridLayout * g2 = new QGridLayout(vl, 2, 2); + + QLabel * label = new QLabel(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, SIGNAL(valueChanged(double)), this, SLOT(slotStrengthChanged(double))); + g2->addWidget(m_strength, 0, 1); + + label = new QLabel(i18n("Wetness:"), this); + g2->addWidget(label, 1, 0); + m_wetness = new KIntNumInput(16, this); + connect(m_wetness, SIGNAL(valueChanged(int)), this, SLOT(slotWetnessChanged(int))); + m_wetness->setRange(0, 16, true); + g2->addWidget(m_wetness, 1, 1); + + g2->addItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum)); + +} + +void KisWetPaletteWidget::update(KisCanvasSubject *subject) +{ + m_subject = subject; + +} + +void KisWetPaletteWidget::slotFGColorSelected(const QColor& c) +{ + KisWetColorSpace* cs = dynamic_cast(KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("WET", ""), "")); + Q_ASSERT(cs); + + WetPack pack; + Q_UINT8* data = reinterpret_cast< Q_UINT8*>(&pack); + cs->fromQColor(c, data); + pack.paint.w = 15 * m_wetness->value(); + // upscale from double to uint16: + pack.paint.h = static_cast< Q_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< Q_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< Q_UINT16>(n * (double)(0xffff/2)); // upscale from double to uint16 + + color.setColor(reinterpret_cast< Q_UINT8*>(&pack), cs); + m_subject->setFGColor(color); +} + + +#include "kis_wet_palette_widget.moc" diff --git a/krita/colorspaces/wet/kis_wet_palette_widget.h b/krita/colorspaces/wet/kis_wet_palette_widget.h new file mode 100644 index 00000000..fb2800d3 --- /dev/null +++ b/krita/colorspaces/wet/kis_wet_palette_widget.h @@ -0,0 +1,67 @@ +/* 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 "qwidget.h" +#include "qpushbutton.h" + +#include "kis_canvas_subject.h" +#include "kis_canvas_observer.h" + +#include + +class KoFrameButton; +class QGridLayout; +class QColor; +class QLabel; +class QSpinBox; +class QColor; +class KIntNumInput; +class KDoubleNumInput; + +class KRITAUI_EXPORT KisWetPaletteWidget + : public QWidget, + public KisCanvasObserver +{ + Q_OBJECT + typedef QWidget super; + +public: + KisWetPaletteWidget(QWidget *parent = 0L, const char *name = 0); + virtual ~KisWetPaletteWidget() {} + +protected slots: + + void slotFGColorSelected(const QColor& 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/krita/colorspaces/wet/kis_wetness_visualisation_filter.cc b/krita/colorspaces/wet/kis_wetness_visualisation_filter.cc new file mode 100644 index 00000000..411a3495 --- /dev/null +++ b/krita/colorspaces/wet/kis_wetness_visualisation_filter.cc @@ -0,0 +1,77 @@ +/* + * kis_wetness_visualisation_filter.cc -- Part of Krita + * + * 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, SIGNAL(timeout()), this, 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/krita/colorspaces/wet/kis_wetness_visualisation_filter.h b/krita/colorspaces/wet/kis_wetness_visualisation_filter.h new file mode 100644 index 00000000..ad5da5d3 --- /dev/null +++ b/krita/colorspaces/wet/kis_wetness_visualisation_filter.h @@ -0,0 +1,50 @@ +/* + * kis_wetness_visualisation_filter.h -- Part of Krita + * + * 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 QObject +{ + Q_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; + QTimer m_timer; +}; + +#endif // _WETNESS_VISUALISATION_FILTER_H diff --git a/krita/colorspaces/wet/kis_wetop.cc b/krita/colorspaces/wet/kis_wetop.cc new file mode 100644 index 00000000..cff3ac1e --- /dev/null +++ b/krita/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(QWidget *parent) + : super(parent) +{ + m_options = new WetPaintOptions(parent, "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(QWidget * parent, const KisInputDevice& inputDevice) +{ + if (inputDevice == KisInputDevice::mouse()) { + // No options for mouse, only tablet devices + return 0; + } else { + return new KisWetOpSettings(parent); + } +} + +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 mask = brush->mask(inf); + dab = computeDab(mask, 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 Q_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 maskW = brush->maskWidth(inf); + int maskH = brush->maskHeight(inf); + KoPoint dest = (pos - (brush->hotSpot(inf))); + int xStart = (int)dest.x(); + int yStart = (int)dest.y(); + + for (int y = 0; y < maskH; y++) { + KisHLineIteratorPixel dabIt = dab->createHLineIterator(0, y, maskW, false); + KisHLineIteratorPixel it = device->createHLineIterator(xStart, yStart+y, maskW, 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(QRect(xStart, yStart, maskW, maskH)); +} diff --git a/krita/colorspaces/wet/kis_wetop.h b/krita/colorspaces/wet/kis_wetop.h new file mode 100644 index 00000000..cc488bf9 --- /dev/null +++ b/krita/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(QWidget * parent, const KisInputDevice& inputDevice); +}; + +class KisWetOpSettings : public KisPaintOpSettings { + typedef KisPaintOpSettings super; +public: + KisWetOpSettings(QWidget *parent); + + bool varySize() const; + bool varyWetness() const; + bool varyStrength() const; + + virtual QWidget *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/krita/colorspaces/wet/kritawetplugin.desktop b/krita/colorspaces/wet/kritawetplugin.desktop new file mode 100644 index 00000000..b6b20e84 --- /dev/null +++ b/krita/colorspaces/wet/kritawetplugin.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=Krita/ColorSpace,Krita/ViewPlugin +Type=Service +X-KDE-Library=kritawetplugin +X-Krita-Version=2 diff --git a/krita/colorspaces/wet/todo b/krita/colorspaces/wet/todo new file mode 100644 index 00000000..2f6d358b --- /dev/null +++ b/krita/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/krita/colorspaces/wet/wdgpressure.ui b/krita/colorspaces/wet/wdgpressure.ui new file mode 100644 index 00000000..92161294 --- /dev/null +++ b/krita/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/krita/colorspaces/wet/wet_plugin.cc b/krita/colorspaces/wet/wet_plugin.cc new file mode 100644 index 00000000..cbb4787b --- /dev/null +++ b/krita/colorspaces/wet/wet_plugin.cc @@ -0,0 +1,128 @@ +/* + * wet_plugin.cc -- Part of Krita + * + * 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( kritawetplugin, WetPluginFactory( "kritacore" ) ) + + +WetPlugin::WetPlugin(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(WetPluginFactory::instance()); + + // This is not a gui plugin; only load it when the doc is created. + if ( parent->inherits("KisColorSpaceFactoryRegistry") ) { + KisColorSpaceFactoryRegistry * f = dynamic_cast(parent); + + 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 (parent->inherits("KisView")) + { + setInstance(WetPluginFactory::instance()); + setXMLFile(locate("data","kritaplugins/wetplugin.rc"), true); + + m_view = dynamic_cast(parent); + // Wetness visualisation + WetnessVisualisationFilter * wf = new WetnessVisualisationFilter(m_view); + wf->setAction(new KToggleAction(i18n("Wetness Visualisation"), 0, 0, wf, + 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", krita::COLORBOX, INT_MAX, PALETTE_DOCKER, false); + m_view->canvasSubject()->attach(w); + } + + +} + +WetPlugin::~WetPlugin() +{ +} + +#include "wet_plugin.moc" diff --git a/krita/colorspaces/wet/wet_plugin.h b/krita/colorspaces/wet/wet_plugin.h new file mode 100644 index 00000000..117ee253 --- /dev/null +++ b/krita/colorspaces/wet/wet_plugin.h @@ -0,0 +1,45 @@ +/* + * 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 +public: + WetPlugin(QObject *parent, const char *name, const QStringList &); + virtual ~WetPlugin(); + +private: + + KisView* m_view; + +}; + +#endif // WET_PLUGIN_H_ diff --git a/krita/colorspaces/wet/wetdreams/Makefile b/krita/colorspaces/wet/wetdreams/Makefile new file mode 100644 index 00000000..3daf4d76 --- /dev/null +++ b/krita/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/krita/colorspaces/wet/wetdreams/wetmain.c b/krita/colorspaces/wet/wetdreams/wetmain.c new file mode 100644 index 00000000..151385f5 --- /dev/null +++ b/krita/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/krita/colorspaces/wet/wetdreams/wetpaint.c b/krita/colorspaces/wet/wetdreams/wetpaint.c new file mode 100644 index 00000000..c1ac0d0c --- /dev/null +++ b/krita/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/krita/colorspaces/wet/wetdreams/wetpaint.h b/krita/colorspaces/wet/wetdreams/wetpaint.h new file mode 100644 index 00000000..5cec2659 --- /dev/null +++ b/krita/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/krita/colorspaces/wet/wetdreams/wetphysics.c b/krita/colorspaces/wet/wetdreams/wetphysics.c new file mode 100644 index 00000000..d8b321a8 --- /dev/null +++ b/krita/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/krita/colorspaces/wet/wetdreams/wetphysics.h b/krita/colorspaces/wet/wetdreams/wetphysics.h new file mode 100644 index 00000000..25140956 --- /dev/null +++ b/krita/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/krita/colorspaces/wet/wetdreams/wetpix.c b/krita/colorspaces/wet/wetdreams/wetpix.c new file mode 100644 index 00000000..812a038d --- /dev/null +++ b/krita/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/krita/colorspaces/wet/wetdreams/wetpix.h b/krita/colorspaces/wet/wetdreams/wetpix.h new file mode 100644 index 00000000..3dc7913f --- /dev/null +++ b/krita/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/krita/colorspaces/wet/wetdreams/wettexture.c b/krita/colorspaces/wet/wetdreams/wettexture.c new file mode 100644 index 00000000..620ad8b5 --- /dev/null +++ b/krita/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/krita/colorspaces/wet/wetdreams/wettexture.h b/krita/colorspaces/wet/wetdreams/wettexture.h new file mode 100644 index 00000000..c3cbc0d2 --- /dev/null +++ b/krita/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/krita/colorspaces/wet/wetphysicsfilter.cc b/krita/colorspaces/wet/wetphysicsfilter.cc new file mode 100644 index 00000000..195a17be --- /dev/null +++ b/krita/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 apparent 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 mask 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 QRect& 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 QRect & 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 masks 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. + Q_INT32 dx, dy; + dx = r.x(); + dy = r.y(); + + int ix = width + 1; // keeps track where we are in the one-dimensional arrays + + for (Q_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 (Q_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 (Q_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 QRect & r) +{ + kdDebug () << "Drying " << r << endl; + for (Q_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); + + Q_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 QRect & r) +{ + kdDebug() << "Adsorbing " << r << endl; + for (Q_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; + Q_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 / QMAX(w, 1); + + wetPixToDouble(&wet_top, paint); + wetPixToDouble(&wet_bot, adsorb); + + mergePixel(&wet_bot, &wet_top, ads, &wet_bot); + wetPixFromDouble(adsorb, &wet_bot); + + paint->rd = (Q_UINT16) (paint->rd*(1 - ads)); + paint->rw = (Q_UINT16) (paint->rw*(1 - ads)); + paint->gd = (Q_UINT16) (paint->gd*(1 - ads)); + paint->gw = (Q_UINT16) (paint->gw*(1 - ads)); + paint->bd = (Q_UINT16) (paint->bd*(1 - ads)); + paint->bw = (Q_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/krita/colorspaces/wet/wetphysicsfilter.h b/krita/colorspaces/wet/wetphysicsfilter.h new file mode 100644 index 00000000..a02f8402 --- /dev/null +++ b/krita/colorspaces/wet/wetphysicsfilter.h @@ -0,0 +1,87 @@ +/* + * This file is part of Krita + * + * 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 QRect; + + +/** + * 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 QRect& 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 QRect & r); + void dry(KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect & r); + + // Move stuff from the upperlayer to the lower layer. This is filter-level stuff. + void adsorb(KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect & 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: + + Q_INT32 m_adsorbCount; + + +}; + +#endif diff --git a/krita/colorspaces/wet/wetplugin.rc b/krita/colorspaces/wet/wetplugin.rc new file mode 100644 index 00000000..39cb6f81 --- /dev/null +++ b/krita/colorspaces/wet/wetplugin.rc @@ -0,0 +1,8 @@ + + + +&View + + + + diff --git a/krita/colorspaces/wetsticky/Makefile.am b/krita/colorspaces/wetsticky/Makefile.am new file mode 100644 index 00000000..70eeb06d --- /dev/null +++ b/krita/colorspaces/wetsticky/Makefile.am @@ -0,0 +1,25 @@ +kde_services_DATA = kritawsplugin.desktop +INCLUDES = -I$(srcdir)/../../sdk \ + -I$(srcdir)/../../core \ + -I$(srcdir)/../../core/color_strategy \ + -I$(srcdir)/../../../kritacolor/color_strategy/ \ + -I$(srcdir)/../../../color_strategy/ \ + -I$(srcdir)/../../ui \ + $(KOFFICE_INCLUDES) \ + -I$(interfacedir) \ + $(KOPAINTER_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = kritawsplugin.la + +kritawsplugin_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 + +kritawsplugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritawsplugin_la_LIBADD = ../../kritacolor/libkritacolor.la + +kritawsplugin_la_METASOURCES = AUTO + +SUBDIRS=brushop + + diff --git a/krita/colorspaces/wetsticky/README b/krita/colorspaces/wetsticky/README new file mode 100644 index 00000000..79a105d4 --- /dev/null +++ b/krita/colorspaces/wetsticky/README @@ -0,0 +1,42 @@ +Wet & Sticky + +The Krita 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 Krita: + +* 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 Krita 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/krita/colorspaces/wetsticky/TODO b/krita/colorspaces/wetsticky/TODO new file mode 100644 index 00000000..513df2ff --- /dev/null +++ b/krita/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/krita/colorspaces/wetsticky/brushop/Makefile.am b/krita/colorspaces/wetsticky/brushop/Makefile.am new file mode 100644 index 00000000..48edd999 --- /dev/null +++ b/krita/colorspaces/wetsticky/brushop/Makefile.am @@ -0,0 +1,28 @@ +kde_services_DATA = kritawsbrushpaintop.desktop + +kritaimagesdir = $(prefix)/share/apps/krita/images +kritaimages_DATA = wetpaintbrush.png + +# all_includes must remain last! +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../kritacolor/color_strategy/ \ + -I$(srcdir)/../../../color_strategy/ \ + -I$(srcdir)/../../../core/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) $(KOPAINTER_INCLUDES) $(all_includes) + + +kritawsbrushpaintop_la_SOURCES = \ + wsbrushpaintop_plugin.cc \ + kis_wsbrushop.cc + +noinst_HEADERS= \ + wsbrushpaintop_plugin.h \ + kis_wsbrushop.h + +kde_module_LTLIBRARIES = kritawsbrushpaintop.la + +kritawsbrushpaintop_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritawsbrushpaintop_la_LIBADD = ../../..//libkritacommon.la $(LIB_KOPAINTER) $(LIB_KOFFICECORE) + +kritawsbrushpaintop_la_METASOURCES = AUTO diff --git a/krita/colorspaces/wetsticky/brushop/README b/krita/colorspaces/wetsticky/brushop/README new file mode 100644 index 00000000..81156a89 --- /dev/null +++ b/krita/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/krita/colorspaces/wetsticky/brushop/kis_wsbrushop.cc b/krita/colorspaces/wetsticky/brushop/kis_wsbrushop.cc new file mode 100644 index 00000000..50b8b4ca --- /dev/null +++ b/krita/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 == mask + // retrieve mask + // else if brush == image + // retrieve image + // subsample (mask | image) for position -- pos should be double! + // apply filters to mask (colour | gradient | pattern | etc. + // composite filtered mask 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. + Q_INT32 x; + double xFraction; + Q_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 mask = brush -> mask(pressure, xFraction, yFraction); + dab = computeDab(mask); + } + m_painter -> setPressure(pressure); + + QRect dabRect = QRect(0, 0, brush -> maskWidth(pressure), brush -> maskHeight(pressure)); + QRect dstRect = QRect(x, y, dabRect.width(), dabRect.height()); + + KisImage * image = device -> image(); + + if (image != 0) { + dstRect &= image -> bounds(); + } + + if (dstRect.isNull() || dstRect.isEmpty() || !dstRect.isValid()) return; + + Q_INT32 sx = dstRect.x() - x; + Q_INT32 sy = dstRect.y() - y; + Q_INT32 sw = dstRect.width(); + Q_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/krita/colorspaces/wetsticky/brushop/kis_wsbrushop.h b/krita/colorspaces/wetsticky/brushop/kis_wsbrushop.h new file mode 100644 index 00000000..34f50207 --- /dev/null +++ b/krita/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 QString 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/krita/colorspaces/wetsticky/brushop/kritawsbrushpaintop.desktop b/krita/colorspaces/wetsticky/brushop/kritawsbrushpaintop.desktop new file mode 100644 index 00000000..d8afc3ed --- /dev/null +++ b/krita/colorspaces/wetsticky/brushop/kritawsbrushpaintop.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=Krita/ColorSpace +Type=Service +X-KDE-Library=kritawsbrushpaintop +X-Krita-Version=2 diff --git a/krita/colorspaces/wetsticky/brushop/wetpaintbrush.png b/krita/colorspaces/wetsticky/brushop/wetpaintbrush.png new file mode 100644 index 00000000..b1b6317d Binary files /dev/null and b/krita/colorspaces/wetsticky/brushop/wetpaintbrush.png differ diff --git a/krita/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.cc b/krita/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.cc new file mode 100644 index 00000000..fe0e1eb4 --- /dev/null +++ b/krita/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.cc @@ -0,0 +1,56 @@ +/* + * wsbrushpaintop_plugin.cc -- Part of Krita + * + * 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( kritawsbrushpaintop, WSBrushPaintOpPluginFactory( "kritacore" ) ) + + +WSBrushPaintOpPlugin::WSBrushPaintOpPlugin(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(WSBrushPaintOpPluginFactory::instance()); + + // This is not a gui plugin; only load it when the doc is created. + if ( parent->inherits("KisFactory") ) + { + KisPaintOpRegistry::instance() -> add ( new KisWSBrushOpFactory ); + } + +} + +WSBrushPaintOpPlugin::~WSBrushPaintOpPlugin() +{ +} + +#include "wsbrushpaintop_plugin.moc" diff --git a/krita/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.h b/krita/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.h new file mode 100644 index 00000000..f668aabf --- /dev/null +++ b/krita/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.h @@ -0,0 +1,43 @@ +/* + * 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 +public: + WSBrushPaintOpPlugin(QObject *parent, const char *name, const QStringList &); + virtual ~WSBrushPaintOpPlugin(); + +private: + + KisView* m_view; +}; + +#endif // WSBRUSH_PAINTOP_PLUGIN_H_ diff --git a/krita/colorspaces/wetsticky/kis_wet_sticky_colorspace.cc b/krita/colorspaces/wetsticky/kis_wet_sticky_colorspace.cc new file mode 100644 index 00000000..c837a558 --- /dev/null +++ b/krita/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, + LIQUID_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) +{ + Q_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 + QValueVector_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::fromQColor(const QColor& c, Q_UINT8 *dst, KisProfile * profile) +{ + CELL_PTR p = (CELL_PTR) dst; + Q_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: (" << QString().setNum(p->red) << ", " + << QString().setNum(p->green) << ", " + << QString().setNum(p->blue) << ", " + << QString().setNum(p->alpha) << ") " + << ", hls: (" << p->hue << ", " + << p->lightness << ", " + << p->saturation << ")\n"; +#endif +} + +void KisWetStickyColorSpace::fromQColor(const QColor& c, Q_UINT8 opacity, Q_UINT8 *dst, KisProfile * profile) +{ + CELL_PTR p = (CELL_PTR) dst; + Q_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: (" << QString().setNum(p->red) << ", " + << QString().setNum(p->green) << ", " + << QString().setNum(p->blue) << ", " + << QString().setNum(p->alpha) << ") " + << ", hls: (" << p->hue << ", " + << p->lightness << ", " + << p->saturation << ")\n"; +#endif +} + +void KisWetStickyColorSpace::toQColor(const Q_UINT8 *src, QColor *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::toQColor(const Q_UINT8 *src, QColor *c, Q_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 Q_UINT8 *src, KisProfile * profile) +{ + return KisPixelRO (src, src, this, profile); +} + +KisPixel KisWetStickyColorSpace::toKisPixel(Q_UINT8 *src, KisProfile * profile) +{ + return KisPixel (src, src, this, profile); +} + +void KisWetStickyColorSpace::mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const +{ +} + +Q_UINT8 KisWetStickyColorSpace::getAlpha(const Q_UINT8 *pixel) const +{ + return ((CELL_PTR)pixel)->alpha; +} + +void KisWetStickyColorSpace::setAlpha(Q_UINT8 * pixels, Q_UINT8 alpha, Q_INT32 nPixels) const +{ + while (nPixels > 0) { + ((CELL_PTR)pixels)->alpha = alpha; + --nPixels; + pixels+=pixelSize(); + } +} + +void KisWetStickyColorSpace::applyAlphaU8Mask(Q_UINT8 * pixels, Q_UINT8 * alpha, Q_INT32 nPixels) +{ +} + +void KisWetStickyColorSpace::applyInverseAlphaU8Mask(Q_UINT8 * pixels, Q_UINT8 * alpha, Q_INT32 nPixels) +{ +} + +Q_UINT8 KisWetStickyColorSpace::scaleToU8(const Q_UINT8 * srcPixel, Q_INT32 channelPos) +{ + return 0; +} + +Q_UINT16 KisWetStickyColorSpace::scaleToU16(const Q_UINT8 * srcPixel, Q_INT32 channelPos) +{ + return 0; +} + + +QValueVector KisWetStickyColorSpace::channels() const +{ + return m_channels; +} + +bool KisWetStickyColorSpace::hasAlpha() const +{ + return true; +} + +Q_INT32 KisWetStickyColorSpace::nChannels() const +{ + return 14; +} + +Q_INT32 KisWetStickyColorSpace::nColorChannels() const +{ + return 3; +} + +Q_INT32 KisWetStickyColorSpace::nSubstanceChannels() const +{ + return 4; + +} + +Q_INT32 KisWetStickyColorSpace::pixelSize() const +{ + return sizeof(CELL); +} + + +QImage KisWetStickyColorSpace::convertToQImage(const Q_UINT8 *data, Q_INT32 width, Q_INT32 height, + KisProfile * /*srcProfile*/, KisProfile * /*dstProfile*/, + Q_INT32 /*renderingIntent*/, float /*exposure*/) +{ + + QImage img(width, height, 32, 0, QImage::LittleEndian); + + Q_INT32 i = 0; + uchar *j = img.bits(); + + CELL_PTR p = (CELL_PTR) data; + + while ( i < width * height) { + + const Q_UINT8 PIXEL_BLUE = 0; + const Q_UINT8 PIXEL_GREEN = 1; + const Q_UINT8 PIXEL_RED = 2; + const Q_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 Q_UINT8 * src, KisProfile * /*srcProfile*/, + Q_UINT8 * dst, KisAbstractColorSpace * dstColorSpace, KisProfile * dstProfile, + Q_UINT32 numPixels, + Q_INT32 /*renderingIntent*/) +{ + Q_INT32 dSize = dstColorSpace -> pixelSize(); + Q_INT32 sSize = pixelSize(); + + Q_UINT32 j = 0; + Q_UINT32 i = 0; + QColor c; + CELL_PTR cp; + while ( i < numPixels ) { + cp = (CELL_PTR) (src + i); + + c.setRgb(cp -> red, + cp -> green, + cp -> blue); + + dstColorSpace -> fromQColor(c, cp -> alpha, (dst + j), dstProfile); + + i += sSize; + j += dSize; + + } + return true; + +} + +void KisWetStickyColorSpace::bitBlt(Q_UINT8 *dst, + Q_INT32 dstRowStride, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 *mask, + Q_INT32 maskRowStride, + Q_UINT8 opacity, + Q_INT32 rows, + Q_INT32 cols, + const KisCompositeOp& op) +{ + switch (op.op()) { + case COMPOSITE_UNDEF: + // Undefined == no composition + break; + case COMPOSITE_OVER: + compositeOver(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY: + default: + compositeCopy(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + } + +} + + +void KisWetStickyColorSpace::compositeOver(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_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 Q_UINT8 *src = srcRowStart; + Q_UINT8 *dst = dstRowStart; + const Q_UINT8 *mask = maskRowStart; + + Q_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 + + Q_UINT8 srcAlpha = srcCell->alpha; + + // apply the alphamask + if(mask != 0) + { + if(*mask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *mask); + mask++; + } + + 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 { + Q_UINT8 dstAlpha = dstCell->alpha; + + Q_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + Q_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(maskRowStart) + maskRowStart += maskRowStride; + } + +} + +void KisWetStickyColorSpace::compositeCopy(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity) +{ + Q_INT32 linesize = sizeof(CELL) * columns; + Q_UINT8 *d; + const Q_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; +} + +QString KisWetStickyColorSpace::channelValueText(const Q_UINT8 *U8_pixel, Q_UINT32 channelIndex) const +{ + Q_ASSERT(channelIndex < nChannels()); + const CELL *pixel = reinterpret_cast(U8_pixel); + + switch (channelIndex) { + case BLUE_CHANNEL_INDEX: + return QString().setNum(pixel -> blue); + case GREEN_CHANNEL_INDEX: + return QString().setNum(pixel -> green); + case RED_CHANNEL_INDEX: + return QString().setNum(pixel -> red); + case ALPHA_CHANNEL_INDEX: + return QString().setNum(pixel -> alpha); + case HUE_CHANNEL_INDEX: + return QString().setNum(pixel -> hue); + case SATURATION_CHANNEL_INDEX: + return QString().setNum(pixel -> saturation); + case LIGHTNESS_CHANNEL_INDEX: + return QString().setNum(pixel -> lightness); + case LIQUID_CONTENT_CHANNEL_INDEX: + return QString().setNum(pixel -> liquid_content); + case DRYING_RATE_CHANNEL_INDEX: + return QString().setNum(pixel -> drying_rate); + case MISCIBILITY_CHANNEL_INDEX: + return QString().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 QString(); + } + } + case GRAVITATIONAL_STRENGTH_CHANNEL_INDEX: + return QString().setNum(pixel -> strength); + case ABSORBANCY_CHANNEL_INDEX: + return QString().setNum(pixel -> absorbancy); + case PAINT_VOLUME_CHANNEL_INDEX: + return QString().setNum(pixel -> volume); + default: + Q_ASSERT(false); + return QString(); + } +} + +QString KisWetStickyColorSpace::normalisedChannelValueText(const Q_UINT8 *U8_pixel, Q_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 QString().setNum(static_cast(pixel -> blue) / UINT8_MAX); + case GREEN_CHANNEL_INDEX: + return QString().setNum(static_cast(pixel -> green) / UINT8_MAX); + case RED_CHANNEL_INDEX: + return QString().setNum(static_cast(pixel -> red) / UINT8_MAX); + case ALPHA_CHANNEL_INDEX: + return QString().setNum(static_cast(pixel -> alpha) / UINT8_MAX); + case HUE_CHANNEL_INDEX: + return QString().setNum(pixel -> hue); + case SATURATION_CHANNEL_INDEX: + return QString().setNum(pixel -> saturation); + case LIGHTNESS_CHANNEL_INDEX: + return QString().setNum(pixel -> lightness); + case LIQUID_CONTENT_CHANNEL_INDEX: + return QString().setNum(static_cast(pixel -> liquid_content) / UINT8_MAX); + case DRYING_RATE_CHANNEL_INDEX: + return QString().setNum(static_cast(pixel -> drying_rate) / UINT8_MAX); + case MISCIBILITY_CHANNEL_INDEX: + return QString().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 QString(); + } + } + case GRAVITATIONAL_STRENGTH_CHANNEL_INDEX: + return QString().setNum(static_cast(pixel -> strength) / UINT8_MAX); + case ABSORBANCY_CHANNEL_INDEX: + return QString().setNum(static_cast(pixel -> absorbancy) / UINT8_MAX); + case PAINT_VOLUME_CHANNEL_INDEX: + return QString().setNum(static_cast(pixel -> volume) / UINT8_MAX); + default: + Q_ASSERT(false); + return QString(); + } +} + diff --git a/krita/colorspaces/wetsticky/kis_wet_sticky_colorspace.h b/krita/colorspaces/wetsticky/kis_wet_sticky_colorspace.h new file mode 100644 index 00000000..758cb57e --- /dev/null +++ b/krita/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 { + Q_UINT8 blue; + Q_UINT8 green; + Q_UINT8 red; + Q_UINT8 alpha; + + float hue; + float saturation; + float lightness; + + Q_UINT8 liquid_content; + Q_UINT8 drying_rate; + Q_UINT8 miscibility; + + enumDirection direction; + Q_UINT8 strength; + + Q_UINT8 absorbancy; /* How much paint can this cell hold? */ + Q_UINT8 volume; /* The volume of paint. */ + + } CELL, *CELL_PTR; + + +} + + + +class KisWetStickyColorSpace : public KisAbstractColorSpace { +public: + KisWetStickyColorSpace(); + virtual ~KisWetStickyColorSpace(); + +public: + + + + virtual void fromQColor(const QColor& c, Q_UINT8 *dst, KisProfile * profile = 0); + virtual void fromQColor(const QColor& c, Q_UINT8 opacity, Q_UINT8 *dst, KisProfile * profile = 0); + + virtual void toQColor(const Q_UINT8 *src, QColor *c, KisProfile * profile = 0); + virtual void toQColor(const Q_UINT8 *src, QColor *c, Q_UINT8 *opacity, KisProfile * profile = 0); + + virtual Q_UINT8 getAlpha(const Q_UINT8 *pixel) const; + virtual void setAlpha(Q_UINT8 * pixels, Q_UINT8 alpha, Q_INT32 nPixels) const; + + virtual void applyAlphaU8Mask(Q_UINT8 * pixels, Q_UINT8 * alpha, Q_INT32 nPixels); + virtual void applyInverseAlphaU8Mask(Q_UINT8 * pixels, Q_UINT8 * alpha, Q_INT32 nPixels); + + virtual Q_UINT8 scaleToU8(const Q_UINT8 * srcPixel, Q_INT32 channelPos); + virtual Q_UINT16 scaleToU16(const Q_UINT8 * srcPixel, Q_INT32 channelPos); + + virtual QValueVector channels() const; + virtual bool hasAlpha() const; + virtual Q_INT32 nChannels() const; + virtual Q_INT32 nColorChannels() const; + virtual Q_INT32 nSubstanceChannels() const; + virtual Q_INT32 pixelSize() const; + + virtual QString channelValueText(const Q_UINT8 *pixel, Q_UINT32 channelIndex) const; + virtual QString normalisedChannelValueText(const Q_UINT8 *pixel, Q_UINT32 channelIndex) const; + + virtual QImage convertToQImage(const Q_UINT8 *data, Q_INT32 width, Q_INT32 height, + KisProfile * srcProfile, KisProfile * dstProfile, + Q_INT32 renderingIntent = INTENT_PERCEPTUAL, + float exposure = 0.0f); + + + virtual void mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const; + virtual void convolveColors(Q_UINT8** colors, Q_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const; + virtual void invertColor(Q_UINT8 * src, Q_INT32 nPixels); + virtual void darken(const Q_UINT8 * src, Q_UINT8 * dst, Q_INT32 shade, bool compensate, double compensation, Q_INT32 nPixels) const; + + virtual KisCompositeOpList userVisiblecompositeOps() const; + +protected: + + virtual void bitBlt(Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 *srcAlphaMask, + Q_INT32 maskRowStride, + Q_UINT8 opacity, + Q_INT32 rows, + Q_INT32 cols, + const KisCompositeOp& op); + + + virtual bool convertPixelsTo(const Q_UINT8 * src, KisProfile * srcProfile, + Q_UINT8 * dst, KisAbstractColorSpace * dstColorSpace, KisProfile * dstProfile, + Q_UINT32 numPixels, + Q_INT32 renderingIntent = INTENT_PERCEPTUAL); + + +private: + + void compositeOver(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeClear(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeCopy(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + +}; + +#endif // KIS_COLORSPACE_WET_STICKY_H_ diff --git a/krita/colorspaces/wetsticky/kis_ws_engine_filter.cc b/krita/colorspaces/wetsticky/kis_ws_engine_filter.cc new file mode 100644 index 00000000..365b5f2a --- /dev/null +++ b/krita/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. + */ +QPoint next_cell(Q_UINT32 width, Q_UINT32 height) +{ + return QPoint(random() * width, random() * height); +} + +void single_step(KisColorSpace * cs, KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect & rect, bool native) +{ + using namespace WetAndSticky; + + + QPoint 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); + + Q_UINT8 *orig = iter.rawData(); + Q_UINT8 *pix = orig; + + if (!orig) return; + + if (!native ) { + QColor c; + Q_UINT8 opacity; + + src -> colorSpace() -> toQColor(pix, &c, &opacity); + Q_UINT8 *pix = new Q_UINT8[sizeof( cell )]; + Q_CHECK_PTR(pix); + + cs -> fromQColor(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 QRect& rect) +{ + + m_src = src; + m_dst = dst; + m_cfg = ( KisWSEngineFilterConfiguration * )configuration; + m_rect = rect; + + + kdDebug(DBG_AREA_FILTERS) << "WSEnginefilter called!\n"; + QTime 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"); + + Q_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 ( Q_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(QWidget* parent, KisPaintDeviceSP dev) +{ +// KisWSEngineFilterConfigurationWidget* kefcw = new KisWSEngineFilterConfigurationWidget(this,parent, ""); +// kdDebug(DBG_AREA_FILTERS) << kefcw << endl; +// return kefcw ; + return 0; +} + +KisFilterConfiguration* KisWSEngineFilter::configuration(QWidget* nwidget, KisPaintDeviceSP dev) +{ +// KisWSEngineFilterConfigurationWidget* widget = (KisWSEngineFilterConfigurationWidget*) nwidget; + +// if( widget == 0 ) +// { +// return new KisWSEngineFilterConfiguration(30); +// } else { +// Q_UINT32 depth = widget -> baseWidget() -> depthSpinBox -> value(); + +// return new KisWSEngineFilterConfiguration(depth); +// } + + + return new KisWSEngineFilterConfiguration( m_rect.height() * m_rect.width() ); +} + diff --git a/krita/colorspaces/wetsticky/kis_ws_engine_filter.h b/krita/colorspaces/wetsticky/kis_ws_engine_filter.h new file mode 100644 index 00000000..5eb8ca81 --- /dev/null +++ b/krita/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(Q_UINT32 pixels = 0) { m_pixels = pixels; } + + Q_UINT32 pixels() { return m_pixels; } + +private: + + Q_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 QRect& 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(QWidget* parent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(QWidget*, KisPaintDeviceSP dev); + + +private: + +private: + + KisWSEngineFilterConfiguration * m_cfg; + KisPaintDeviceSP m_src; + KisPaintDeviceSP m_dst; + QRect m_rect; + +}; + +#endif // _KIS_WS_ENGINE_FILTER_H_ diff --git a/krita/colorspaces/wetsticky/kritawsplugin.desktop b/krita/colorspaces/wetsticky/kritawsplugin.desktop new file mode 100644 index 00000000..0f6b6791 --- /dev/null +++ b/krita/colorspaces/wetsticky/kritawsplugin.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=Krita/ColorSpace +Type=Service +X-KDE-Library=kritawsplugin +X-Krita-Version=2 + diff --git a/krita/colorspaces/wetsticky/wet_sticky_plugin.cc b/krita/colorspaces/wetsticky/wet_sticky_plugin.cc new file mode 100644 index 00000000..858b4810 --- /dev/null +++ b/krita/colorspaces/wetsticky/wet_sticky_plugin.cc @@ -0,0 +1,60 @@ +/* + * wet_sticky_plugin.cc -- Part of Krita + * + * 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( kritawsplugin, WetStickyPluginFactory( "kritacore" ) ) + + +WetStickyPlugin::WetStickyPlugin(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(WetStickyPluginFactory::instance()); + + // This is not a gui plugin; only load it when the doc is created. + if ( parent->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/krita/colorspaces/wetsticky/wet_sticky_plugin.h b/krita/colorspaces/wetsticky/wet_sticky_plugin.h new file mode 100644 index 00000000..35b8207c --- /dev/null +++ b/krita/colorspaces/wetsticky/wet_sticky_plugin.h @@ -0,0 +1,41 @@ +/* + * 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 +public: + WetStickyPlugin(QObject *parent, const char *name, const QStringList &); + virtual ~WetStickyPlugin(); + +}; + +#endif // WET_STICKY_PLUGIN_H_ diff --git a/krita/colorspaces/wetsticky/ws/GNU b/krita/colorspaces/wetsticky/ws/GNU new file mode 100644 index 00000000..e69de29b diff --git a/krita/colorspaces/wetsticky/ws/GNU Public Licence.txt b/krita/colorspaces/wetsticky/ws/GNU Public Licence.txt new file mode 100644 index 00000000..a3f2100e --- /dev/null +++ b/krita/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 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/krita/colorspaces/wetsticky/ws/README b/krita/colorspaces/wetsticky/ws/README new file mode 100644 index 00000000..15f55e77 --- /dev/null +++ b/krita/colorspaces/wetsticky/ws/README @@ -0,0 +1,4 @@ + +The gear example + +This example program demonstrates how to use OpenGL display lists. diff --git a/krita/colorspaces/wetsticky/ws/TODO b/krita/colorspaces/wetsticky/ws/TODO new file mode 100644 index 00000000..91c48a03 --- /dev/null +++ b/krita/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/krita/colorspaces/wetsticky/ws/after.jpg b/krita/colorspaces/wetsticky/ws/after.jpg new file mode 100644 index 00000000..5116efdb Binary files /dev/null and b/krita/colorspaces/wetsticky/ws/after.jpg differ diff --git a/krita/colorspaces/wetsticky/ws/anim.c b/krita/colorspaces/wetsticky/ws/anim.c new file mode 100644 index 00000000..fed5379f --- /dev/null +++ b/krita/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 mask; +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); + + mask = GCBackground| GCForeground| GCFunction; + + values.function = GXcopy; + values.background = 0; + values.foreground = 1; + + + gc = XtGetGC(colour_canvas, mask, &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/krita/colorspaces/wetsticky/ws/before.jpg b/krita/colorspaces/wetsticky/ws/before.jpg new file mode 100644 index 00000000..fc26b989 Binary files /dev/null and b/krita/colorspaces/wetsticky/ws/before.jpg differ diff --git a/krita/colorspaces/wetsticky/ws/canvas.c b/krita/colorspaces/wetsticky/ws/canvas.c new file mode 100644 index 00000000..d2e27cd1 --- /dev/null +++ b/krita/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_repaint() routine + and are removed by the next_cell_for_repaint() function. The + pointer to the current tail of the list is updated by side-effect. */ + +static POINT need_repainting[REDRAW_LIMIT]; +static int next_free = 0; +static int next_to_repaint = 0; + +/* *********************************************************************** */ + +int number_of_repaints_needed() +/* Returns the number of cells that need to be repainted. */ + +{ + return (next_free); +} + +/* *********************************************************************** */ + +void need_to_repaint(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 repainting operation and only add it if + it is not there. */ + +POINT point; + +{ + int k; + + + /* If the list is already full then simply ignore the repaint + 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_repainting[k].x == point.x) && + (need_repainting[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_repainting[next_free].x = point.x; + need_repainting[next_free].y = point.y; + next_free++; +} + +/* *********************************************************************** */ + +void next_cell_for_repaint(cell, locus) +/* This routine returns the next cell to be repainted, together with its + location on the canvas. This is determined by taking the next point + from the need_repainting list and accessing its cell. If the list is + empty then return NIL. + Note that the repainting operation will clear out the list before + any other new positions are added. */ + + CELL_PTR *cell; + POINT_PTR locus; + +{ + if (next_to_repaint >= next_free) { + next_to_repaint = next_free = 0; + *(cell) = NIL; + return; + } + + *(cell) = get_cell(need_repainting[next_to_repaint]); + locus->x = need_repainting[next_to_repaint].x; + locus->y = need_repainting[next_to_repaint].y; + next_to_repaint++; +} + +/* *********************************************************************** */ + +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/krita/colorspaces/wetsticky/ws/canvas.h b/krita/colorspaces/wetsticky/ws/canvas.h new file mode 100644 index 00000000..2df50140 --- /dev/null +++ b/krita/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_repaints_needed(); +/* Returns the number of cells needing to repainted. */ + +extern void need_to_repaint (/* POINT */); +/* Requests that the cell at the given point be repainted + at the next update as it has been modified. */ + +extern void next_cell_for_repaint (/* *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/krita/colorspaces/wetsticky/ws/cmap.c b/krita/colorspaces/wetsticky/ws/cmap.c new file mode 100644 index 00000000..9e53b0ae --- /dev/null +++ b/krita/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 mask; +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 mask; + + values.background = colours[0].pixel; + values.foreground = colours[255].pixel;; + values.fill_style = FillSolid; + values.function = GXclear; + + + mask = GCBackground| GCForeground| GCFillStyle | GCFunction; + + tmp_gc = XtGetGC(top_level, mask, &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); + + mask = GCBackground| GCForeground| GCFunction; + + values.function = GXcopy; + values.background = colours[0].pixel; + values.foreground = colours[255].pixel; + + + gc = XtGetGC(colour_canvas, mask, &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/krita/colorspaces/wetsticky/ws/constants.h b/krita/colorspaces/wetsticky/ws/constants.h new file mode 100644 index 00000000..fa72bc92 --- /dev/null +++ b/krita/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/krita/colorspaces/wetsticky/ws/engine.c b/krita/colorspaces/wetsticky/ws/engine.c new file mode 100644 index 00000000..19097d9f --- /dev/null +++ b/krita/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 repainting. + + 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_repaint(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/krita/colorspaces/wetsticky/ws/engine.h b/krita/colorspaces/wetsticky/ws/engine.h new file mode 100644 index 00000000..b6072b0a --- /dev/null +++ b/krita/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/krita/colorspaces/wetsticky/ws/engine3.c b/krita/colorspaces/wetsticky/ws/engine3.c new file mode 100644 index 00000000..03a7d4f3 --- /dev/null +++ b/krita/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 repainting. + + 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_repaint(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/krita/colorspaces/wetsticky/ws/load_ppm.c b/krita/colorspaces/wetsticky/ws/load_ppm.c new file mode 100644 index 00000000..6368ee08 --- /dev/null +++ b/krita/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/krita/colorspaces/wetsticky/ws/main.c b/krita/colorspaces/wetsticky/ws/main.c new file mode 100644 index 00000000..8185557a --- /dev/null +++ b/krita/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/krita/colorspaces/wetsticky/ws/makefile b/krita/colorspaces/wetsticky/ws/makefile new file mode 100644 index 00000000..a14beb9a --- /dev/null +++ b/krita/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/krita/colorspaces/wetsticky/ws/mona.pgm b/krita/colorspaces/wetsticky/ws/mona.pgm new file mode 100644 index 00000000..2060ee90 Binary files /dev/null and b/krita/colorspaces/wetsticky/ws/mona.pgm differ diff --git a/krita/colorspaces/wetsticky/ws/ogl_interface.c b/krita/colorspaces/wetsticky/ws/ogl_interface.c new file mode 100644 index 00000000..76a552a9 --- /dev/null +++ b/krita/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_repaint(&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/krita/colorspaces/wetsticky/ws/test2.jpg b/krita/colorspaces/wetsticky/ws/test2.jpg new file mode 100644 index 00000000..24b92c3d Binary files /dev/null and b/krita/colorspaces/wetsticky/ws/test2.jpg differ diff --git a/krita/colorspaces/wetsticky/ws/test3.jpg b/krita/colorspaces/wetsticky/ws/test3.jpg new file mode 100644 index 00000000..2b25a0d5 Binary files /dev/null and b/krita/colorspaces/wetsticky/ws/test3.jpg differ diff --git a/krita/colorspaces/wetsticky/ws/types.h b/krita/colorspaces/wetsticky/ws/types.h new file mode 100644 index 00000000..af671f53 --- /dev/null +++ b/krita/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/krita/colorspaces/wetsticky/ws/win_interface.h b/krita/colorspaces/wetsticky/ws/win_interface.h new file mode 100644 index 00000000..ee7a064b --- /dev/null +++ b/krita/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/krita/colorspaces/wetsticky/ws/x_interface.c b/krita/colorspaces/wetsticky/ws/x_interface.c new file mode 100644 index 00000000..f4cb4901 --- /dev/null +++ b/krita/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 mask; +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 mask; + + values.background = colours[0].pixel; + values.foreground = colours[255].pixel;; + values.fill_style = FillSolid; + values.function = GXclear; + + + mask = GCBackground| GCForeground| GCFillStyle | GCFunction; + + tmp_gc = XtGetGC(top_level, mask, &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); + + mask = GCBackground| GCForeground| GCFunction; + + values.function = GXcopy; + values.background = colours[0].pixel; + values.foreground = colours[255].pixel; + + + gc = XtGetGC(colour_canvas, mask, &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_repaint(&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/krita/colorspaces/wetsticky/wstool.ui b/krita/colorspaces/wetsticky/wstool.ui new file mode 100644 index 00000000..4dab3233 --- /dev/null +++ b/krita/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/krita/colorspaces/ycbcr_u16/Makefile.am b/krita/colorspaces/ycbcr_u16/Makefile.am new file mode 100644 index 00000000..5dbfac1b --- /dev/null +++ b/krita/colorspaces/ycbcr_u16/Makefile.am @@ -0,0 +1,27 @@ +# Install the desktop file needed to detect the plugin +kde_services_DATA = krita_ycbcr_u16_plugin.desktop + +INCLUDES = -I$(srcdir)/../../sdk \ + -I$(srcdir)/../../kritacolor/color_strategy/ \ + -I$(srcdir)/../../kritacolor/ \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +lib_LTLIBRARIES = libkrita_ycbcr_u16.la + +libkrita_ycbcr_u16_la_LDFLAGS = $(all_libraries) +libkrita_ycbcr_u16_la_LIBADD = ../../kritacolor/libkritacolor.la + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = krita_ycbcr_u16_plugin.la + +# Srcs for the plugin +krita_ycbcr_u16_plugin_la_SOURCES = ycbcr_u16_plugin.cc +noinst_HEADERS = ycbcr_u16_plugin.h kis_ycbcr_u16_colorspace.h + +krita_ycbcr_u16_plugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +krita_ycbcr_u16_plugin_la_LIBADD = libkrita_ycbcr_u16.la ../../kritacolor/libkritacolor.la + +METASOURCES = AUTO + +libkrita_ycbcr_u16_la_SOURCES = kis_ycbcr_u16_colorspace.cc diff --git a/krita/colorspaces/ycbcr_u16/kis_ycbcr_u16_colorspace.cc b/krita/colorspaces/ycbcr_u16/kis_ycbcr_u16_colorspace.cc new file mode 100644 index 00000000..3155457f --- /dev/null +++ b/krita/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 Q_INT32 MAX_CHANNEL_YCbCr = 3; +const Q_INT32 MAX_CHANNEL_YCbCrA = 4; + +KisYCbCrU16ColorSpace::KisYCbCrU16ColorSpace(KisColorSpaceFactoryRegistry* parent, KisProfile* /*p*/) + : KisU16BaseColorSpace(KisID("YCbCrAU16", i18n("YCbCr (16-bit integer/channel)")), TYPE_YCbCr_16, icSigYCbCrData, parent, 0) +{ + m_channels.push_back(new KisChannelInfo(i18n("Y"), "Y", PIXEL_Y * sizeof(Q_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(Q_UINT16))); + m_channels.push_back(new KisChannelInfo(i18n("Cb"), "Cb", PIXEL_Cb * sizeof(Q_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(Q_UINT16))); + m_channels.push_back(new KisChannelInfo(i18n("Cr"), "Cr", PIXEL_Cr * sizeof(Q_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(Q_UINT16))); + m_channels.push_back(new KisChannelInfo(i18n("Alpha"), "A", PIXEL_ALPHA * sizeof(Q_UINT16), KisChannelInfo::ALPHA, KisChannelInfo::UINT16, sizeof(Q_UINT16))); + + m_alphaPos = PIXEL_ALPHA * sizeof(Q_UINT16); + KisAbstractColorSpace::init(); +} + + +KisYCbCrU16ColorSpace::~KisYCbCrU16ColorSpace() +{ +} + +void KisYCbCrU16ColorSpace::setPixel(Q_UINT8 *dst, Q_UINT16 Y, Q_UINT16 Cb, Q_UINT16 Cr, Q_UINT16 alpha) const +{ + Pixel *dstPixel = reinterpret_cast(dst); + + dstPixel->Y = Y; + dstPixel->Cb = Cb; + dstPixel->Cr = Cr; + dstPixel->alpha = alpha; +} + +void KisYCbCrU16ColorSpace::getPixel(const Q_UINT8 *src, Q_UINT16 *Y, Q_UINT16 *Cb, Q_UINT16 *Cr, Q_UINT16 *alpha) const +{ + const Pixel *srcPixel = reinterpret_cast(src); + + *Y = srcPixel->Y; + *Cb = srcPixel->Cb; + *Cr = srcPixel->Cr; + *alpha = srcPixel->alpha; + +} + +void KisYCbCrU16ColorSpace::fromQColor(const QColor& c, Q_UINT8 *dstU8, KisProfile * profile ) +{ + if(getProfile()) + { + KisU16BaseColorSpace::fromQColor(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::fromQColor(const QColor& c, Q_UINT8 opacity, Q_UINT8 *dstU8, KisProfile * profile ) +{ + if(getProfile()) + { + KisU16BaseColorSpace::fromQColor(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::toQColor(const Q_UINT8 *srcU8, QColor *c, KisProfile * profile) +{ + if(getProfile()) + { + KisU16BaseColorSpace::toQColor(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::toQColor(const Q_UINT8 *srcU8, QColor *c, Q_UINT8 *opacity, KisProfile * profile) +{ + if(getProfile()) + { + KisU16BaseColorSpace::toQColor(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; + } +} + +Q_UINT8 KisYCbCrU16ColorSpace::difference(const Q_UINT8 *src1U8, const Q_UINT8 *src2U8) +{ + if(getProfile()) + return KisU16BaseColorSpace::difference(src1U8, src2U8); + const Pixel *src1 = reinterpret_cast(src1U8); + const Pixel *src2 = reinterpret_cast(src2U8); + + return QMAX(QABS(src2->Y - src1->Y), QMAX(QABS(src2->Cb - src1->Cb), QABS(src2->Cr - src1->Cr))) >> 8; + +} + +void KisYCbCrU16ColorSpace::mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const +{ + Q_UINT16 totalY = 0, totalCb = 0, totalCr = 0, newAlpha = 0; + + while (nColors--) + { + const Pixel *pixel = reinterpret_cast(*colors); + + Q_UINT16 alpha = pixel->alpha; + float alphaTimesWeight = alpha * *weights; + + totalY += (Q_UINT16)(pixel->Y * alphaTimesWeight); + totalCb += (Q_UINT16)(pixel->Cb * alphaTimesWeight); + totalCr += (Q_UINT16)(pixel->Cr * alphaTimesWeight); + newAlpha += (Q_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; +} + +QValueVector KisYCbCrU16ColorSpace::channels() const { + return m_channels; +} + +Q_UINT32 KisYCbCrU16ColorSpace::nChannels() const { + return MAX_CHANNEL_YCbCrA; +} + +Q_UINT32 KisYCbCrU16ColorSpace::nColorChannels() const { + return MAX_CHANNEL_YCbCr; +} + +Q_UINT32 KisYCbCrU16ColorSpace::pixelSize() const { + return MAX_CHANNEL_YCbCrA * sizeof(Q_UINT16); +} + + +QImage KisYCbCrU16ColorSpace::convertToQImage(const Q_UINT8 *data, Q_INT32 width, Q_INT32 height, KisProfile * dstProfile, Q_INT32 renderingIntent, float exposure ) +{ + if(getProfile()) + return KisU16BaseColorSpace::convertToQImage( data, width, height, dstProfile, renderingIntent, exposure); + + QImage img = QImage(width, height, 32, 0, QImage::LittleEndian); + img.setAlphaBuffer(true); + + Q_INT32 i = 0; + uchar *j = img.bits(); + + while ( i < width * height * MAX_CHANNEL_YCbCrA) { + Q_UINT16 Y = *( data + i + PIXEL_Y ); + Q_UINT16 Cb = *( data + i + PIXEL_Cb ); + Q_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(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *srcAlphaMask, Q_INT32 maskRowStride, Q_UINT8 opacity, Q_INT32 rows, Q_INT32 cols, const KisCompositeOp& op) +{ + switch (op.op()) { + case COMPOSITE_UNDEF: + // Undefined == no composition + break; + case COMPOSITE_OVER: + compositeOver(dst, dstRowStride, src, srcRowStride, srcAlphaMask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY: + compositeCopy(dst, dstRowStride, src, srcRowStride, srcAlphaMask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ERASE: + compositeErase(dst, dstRowStride, src, srcRowStride, srcAlphaMask, maskRowStride, rows, cols, opacity); + break; + default: + break; + } +} + +void KisYCbCrU16ColorSpace::compositeOver(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + while (rows > 0) { + + const Q_UINT16 *src = reinterpret_cast(srcRowStart); + Q_UINT16 *dst = reinterpret_cast(dstRowStart); + const Q_UINT8 *mask = maskRowStart; + Q_INT32 columns = numColumns; + + while (columns > 0) { + + Q_UINT16 srcAlpha = src[PIXEL_ALPHA]; + + // apply the alphamask + if (mask != 0) { + Q_UINT8 U8_mask = *mask; + + if (U8_mask != OPACITY_OPAQUE) { + srcAlpha = UINT16_MULT(srcAlpha, UINT8_TO_UINT16(U8_mask)); + } + mask++; + } + + 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(Q_UINT16)); + } else { + Q_UINT16 dstAlpha = dst[PIXEL_ALPHA]; + + Q_UINT16 srcBlend; + + if (dstAlpha == U16_OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + Q_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(Q_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(maskRowStart) { + maskRowStart += maskRowStride; + } + } +} + +void KisYCbCrU16ColorSpace::compositeErase(Q_UINT8 *dst, Q_INT32 dstRowSize, const Q_UINT8 *src, Q_INT32 srcRowSize, const Q_UINT8 *srcAlphaMask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 cols, Q_UINT8 /*opacity*/) +{ + while (rows-- > 0) + { + const Pixel *s = reinterpret_cast(src); + Pixel *d = reinterpret_cast(dst); + const Q_UINT8 *mask = srcAlphaMask; + + for (Q_INT32 i = cols; i > 0; i--, s++, d++) + { + Q_UINT16 srcAlpha = s->alpha; + + // apply the alphamask + if (mask != 0) { + Q_UINT8 U8_mask = *mask; + + if (U8_mask != OPACITY_OPAQUE) { + srcAlpha = UINT16_BLEND(srcAlpha, U16_OPACITY_OPAQUE, UINT8_TO_UINT16(U8_mask)); + } + mask++; + } + d->alpha = UINT16_MULT(srcAlpha, d->alpha); + } + + dst += dstRowSize; + src += srcRowSize; + if(srcAlphaMask) { + srcAlphaMask += maskRowStride; + } + } +} + +KisCompositeOpList KisYCbCrU16ColorSpace::userVisiblecompositeOps() const +{ + KisCompositeOpList list; + + list.append(KisCompositeOp(COMPOSITE_OVER)); + return list; +} diff --git a/krita/colorspaces/ycbcr_u16/kis_ycbcr_u16_colorspace.h b/krita/colorspaces/ycbcr_u16/kis_ycbcr_u16_colorspace.h new file mode 100644 index 00000000..b2dcd341 --- /dev/null +++ b/krita/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* parent, KisProfile* p); + ~KisYCbCrU16ColorSpace(); + virtual bool willDegrade(ColorSpaceIndependence ) + { + return false; + }; + public: + void setPixel(Q_UINT8 *pixel, Q_UINT16 Y, Q_UINT16 Cb, Q_UINT16 Cr, Q_UINT16 alpha) const; + void getPixel(const Q_UINT8 *pixel, Q_UINT16 *Y, Q_UINT16 *Cb, Q_UINT16 *Cr, Q_UINT16 *alpha) const; + + virtual void fromQColor(const QColor& c, Q_UINT8 *dst, KisProfile * profile = 0); + virtual void fromQColor(const QColor& c, Q_UINT8 opacity, Q_UINT8 *dst, KisProfile * profile = 0); + + virtual void toQColor(const Q_UINT8 *src, QColor *c, KisProfile * profile = 0); + virtual void toQColor(const Q_UINT8 *src, QColor *c, Q_UINT8 *opacity, KisProfile * profile = 0); + + virtual Q_UINT8 difference(const Q_UINT8 *src1, const Q_UINT8 *src2); + virtual void mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const; + + virtual QValueVector channels() const; + virtual Q_UINT32 nChannels() const; + virtual Q_UINT32 nColorChannels() const; + virtual Q_UINT32 pixelSize() const; + + virtual QImage convertToQImage(const Q_UINT8 *data, Q_INT32 width, Q_INT32 height, + KisProfile * dstProfile, + Q_INT32 renderingIntent, + float exposure = 0.0f); + + virtual KisCompositeOpList userVisiblecompositeOps() const; + + protected: + + virtual void bitBlt(Q_UINT8 *dst, + Q_INT32 dstRowStride, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 *srcAlphaMask, + Q_INT32 maskRowStride, + Q_UINT8 opacity, + Q_INT32 rows, + Q_INT32 cols, + const KisCompositeOp& op); + + void compositeOver(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeErase(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + + private: +#define CLAMP_TO_16BITCHANNEL(a) CLAMP(a, 0, Q_UINT16_MAX) + inline Q_UINT16 computeRed(Q_UINT16 Y, Q_UINT16 /*Cb*/, Q_UINT16 Cr) + { + return (Q_UINT16)( CLAMP_TO_16BITCHANNEL( (Cr - 32768)* (2-2*LUMA_RED) + Y ) ); + } + inline Q_UINT16 computeGreen(Q_UINT16 Y, Q_UINT16 Cb, Q_UINT16 Cr) + { + return (Q_UINT16)( CLAMP_TO_16BITCHANNEL( (Y - LUMA_BLUE * computeBlue(Y,Cb,Cr) - LUMA_RED * computeRed(Y,Cb,Cr) ) / LUMA_GREEN ) ); + } + inline Q_UINT16 computeBlue(Q_UINT16 Y, Q_UINT16 Cb, Q_UINT16 /*Cr*/) + { + return (Q_UINT16)( CLAMP_TO_16BITCHANNEL( (Cb - 32768)*(2 - 2 * LUMA_BLUE) + Y) ); + } + inline Q_UINT16 computeY( Q_UINT16 r, Q_UINT16 b, Q_UINT16 g) + { + return (Q_UINT16)( CLAMP_TO_16BITCHANNEL( LUMA_RED*r + LUMA_GREEN*g + LUMA_BLUE*b ) ); + } + inline Q_UINT16 computeCb( Q_UINT16 r, Q_UINT16 b, Q_UINT16 g) + { + return (Q_UINT16)( CLAMP_TO_16BITCHANNEL( (b - computeY(r,g,b))/(2-2*LUMA_BLUE) + 32768) ); + } + inline Q_UINT16 computeCr( Q_UINT16 r, Q_UINT16 b, Q_UINT16 g) + { + return (Q_UINT8)( CLAMP_TO_16BITCHANNEL( (r - computeY(r,g,b))/(2-2*LUMA_RED) + 32768) ); + } +#undef CLAMP_TO_16BITCHANNEL + + static const Q_UINT8 PIXEL_Y = 0; + static const Q_UINT8 PIXEL_Cb = 1; + static const Q_UINT8 PIXEL_Cr = 2; + static const Q_UINT8 PIXEL_ALPHA = 3; + + struct Pixel { + Q_UINT16 Y; + Q_UINT16 Cb; + Q_UINT16 Cr; + Q_UINT16 alpha; + }; +}; + +class KisYCbCrU16ColorSpaceFactory : public KisColorSpaceFactory +{ + public: + /** + * Krita 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 Q_UINT32 colorSpaceType() { return TYPE_YCbCr_16; }; + + virtual icColorSpaceSignature colorSpaceSignature() { return icSigYCbCrData; }; + + virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) { return new KisYCbCrU16ColorSpace(parent, p); }; + + virtual QString defaultProfile() { return ""; }; +}; + + +#endif diff --git a/krita/colorspaces/ycbcr_u16/krita_ycbcr_u16_plugin.desktop b/krita/colorspaces/ycbcr_u16/krita_ycbcr_u16_plugin.desktop new file mode 100644 index 00000000..3581582d --- /dev/null +++ b/krita/colorspaces/ycbcr_u16/krita_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=Krita/ColorSpace +Type=Service +X-KDE-Library=krita_ycbcr_u16_plugin +X-Krita-Version=2 diff --git a/krita/colorspaces/ycbcr_u16/ycbcr_u16_plugin.cc b/krita/colorspaces/ycbcr_u16/ycbcr_u16_plugin.cc new file mode 100644 index 00000000..0ab9ed4b --- /dev/null +++ b/krita/colorspaces/ycbcr_u16/ycbcr_u16_plugin.cc @@ -0,0 +1,60 @@ +/* + * ycbcr_u16_plugin.cc -- Part of Krita + * + * 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( krita_ycbcr_u16_plugin, YCbCrU16PluginFactory( "krita" ) ) + + +YCbCrU16Plugin::YCbCrU16Plugin(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(YCbCrU16PluginFactory::instance()); + + if ( parent->inherits("KisColorSpaceFactoryRegistry") ) + { + KisColorSpaceFactoryRegistry * f = dynamic_cast( parent ); + + 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/krita/colorspaces/ycbcr_u16/ycbcr_u16_plugin.h b/krita/colorspaces/ycbcr_u16/ycbcr_u16_plugin.h new file mode 100644 index 00000000..3b079ee7 --- /dev/null +++ b/krita/colorspaces/ycbcr_u16/ycbcr_u16_plugin.h @@ -0,0 +1,37 @@ +/* + * 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 +public: + YCbCrU16Plugin(QObject *parent, const char *name, const QStringList &); + virtual ~YCbCrU16Plugin(); + +}; + + +#endif // YCBCR_U16_PLUGIN_H_ diff --git a/krita/colorspaces/ycbcr_u8/Makefile.am b/krita/colorspaces/ycbcr_u8/Makefile.am new file mode 100644 index 00000000..bb534bc1 --- /dev/null +++ b/krita/colorspaces/ycbcr_u8/Makefile.am @@ -0,0 +1,29 @@ +# Install the desktop file needed to detect the plugin + + +INCLUDES = -I$(srcdir)/../../sdk \ + -I$(srcdir)/../../kritacolor/color_strategy/ \ + -I$(srcdir)/../../kritacolor/ \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +lib_LTLIBRARIES = libkrita_ycbcr_u8.la + +libkrita_ycbcr_u8_la_LDFLAGS = $(all_libraries) +libkrita_ycbcr_u8_la_LIBADD = ../../kritacolor/libkritacolor.la + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = krita_ycbcr_u8_plugin.la + +# Srcs for the plugin +krita_ycbcr_u8_plugin_la_SOURCES = ycbcr_u8_plugin.cc +noinst_HEADERS = ycbcr_u8_plugin.h kis_ycbcr_u8_colorspace.h + +krita_ycbcr_u8_plugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +krita_ycbcr_u8_plugin_la_LIBADD = libkrita_ycbcr_u8.la ../../kritacolor/libkritacolor.la + +METASOURCES = AUTO + + +libkrita_ycbcr_u8_la_SOURCES = kis_ycbcr_u8_colorspace.cc +kde_services_DATA = krita_ycbcr_u8_plugin.desktop diff --git a/krita/colorspaces/ycbcr_u8/kis_ycbcr_u8_colorspace.cc b/krita/colorspaces/ycbcr_u8/kis_ycbcr_u8_colorspace.cc new file mode 100644 index 00000000..7c6707c5 --- /dev/null +++ b/krita/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 Q_INT32 MAX_CHANNEL_YCbCr = 3; +const Q_INT32 MAX_CHANNEL_YCbCrA = 4; + +KisYCbCrU8ColorSpace::KisYCbCrU8ColorSpace(KisColorSpaceFactoryRegistry* parent, KisProfile* /*p*/) + : KisU8BaseColorSpace(KisID("YCbCrAU8", i18n("YCbCr (8-bit integer/channel)")), TYPE_YCbCr_8, icSigYCbCrData, parent, 0) +{ + m_channels.push_back(new KisChannelInfo(i18n("Y"), "Y", PIXEL_Y * sizeof(Q_UINT8), KisChannelInfo::COLOR, KisChannelInfo::UINT8, sizeof(Q_UINT8))); + m_channels.push_back(new KisChannelInfo(i18n("Cb"), "Cb", PIXEL_Cb * sizeof(Q_UINT8), KisChannelInfo::COLOR, KisChannelInfo::UINT8, sizeof(Q_UINT8))); + m_channels.push_back(new KisChannelInfo(i18n("Cr"), "Cr", PIXEL_Cr * sizeof(Q_UINT8), KisChannelInfo::COLOR, KisChannelInfo::UINT8, sizeof(Q_UINT8))); + m_channels.push_back(new KisChannelInfo(i18n("Alpha"), "A", PIXEL_ALPHA * sizeof(Q_UINT8), KisChannelInfo::ALPHA, KisChannelInfo::UINT8, sizeof(Q_UINT8))); + + m_alphaPos = PIXEL_ALPHA * sizeof(Q_UINT8); + KisAbstractColorSpace::init(); +} + + +KisYCbCrU8ColorSpace::~KisYCbCrU8ColorSpace() +{ +} + +void KisYCbCrU8ColorSpace::setPixel(Q_UINT8 *dst, Q_UINT8 Y, Q_UINT8 Cb, Q_UINT8 Cr, Q_UINT8 alpha) const +{ + Pixel *dstPixel = reinterpret_cast(dst); + + dstPixel->Y = Y; + dstPixel->Cb = Cb; + dstPixel->Cr = Cr; + dstPixel->alpha = alpha; +} + +void KisYCbCrU8ColorSpace::getPixel(const Q_UINT8 *src, Q_UINT8 *Y, Q_UINT8 *Cb, Q_UINT8 *Cr, Q_UINT8 *alpha) const +{ + const Pixel *srcPixel = reinterpret_cast(src); + + *Y = srcPixel->Y; + *Cb = srcPixel->Cb; + *Cr = srcPixel->Cr; + *alpha = srcPixel->alpha; + +} + +void KisYCbCrU8ColorSpace::fromQColor(const QColor& c, Q_UINT8 *dstU8, KisProfile * profile ) +{ + if(getProfile()) + { + KisU8BaseColorSpace::fromQColor(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::fromQColor(const QColor& c, Q_UINT8 opacity, Q_UINT8 *dstU8, KisProfile * profile ) +{ + if(getProfile()) + { + KisU8BaseColorSpace::fromQColor(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::toQColor(const Q_UINT8 *srcU8, QColor *c, KisProfile * profile) +{ + if(getProfile()) + { + KisU8BaseColorSpace::toQColor(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::toQColor(const Q_UINT8 *srcU8, QColor *c, Q_UINT8 *opacity, KisProfile * profile) +{ + if(getProfile()) + { + KisU8BaseColorSpace::toQColor(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; + } +} + +Q_UINT8 KisYCbCrU8ColorSpace::difference(const Q_UINT8 *src1U8, const Q_UINT8 *src2U8) +{ + if(getProfile()) + return KisU8BaseColorSpace::difference(src1U8, src2U8); + const Pixel *src1 = reinterpret_cast(src1U8); + const Pixel *src2 = reinterpret_cast(src2U8); + + return QMAX(QABS(src2->Y - src1->Y), QMAX(QABS(src2->Cb - src1->Cb), QABS(src2->Cr - src1->Cr))); + +} + +void KisYCbCrU8ColorSpace::mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const +{ + Q_UINT8 totalY = 0, totalCb = 0, totalCr = 0, newAlpha = 0; + + while (nColors--) + { + const Pixel *pixel = reinterpret_cast(*colors); + + Q_UINT8 alpha = pixel->alpha; + float alphaTimesWeight = alpha * *weights; + + totalY += (Q_UINT8)(pixel->Y * alphaTimesWeight); + totalCb += (Q_UINT8)(pixel->Cb * alphaTimesWeight); + totalCr += (Q_UINT8)(pixel->Cr * alphaTimesWeight); + newAlpha += (Q_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; +} + +QValueVector KisYCbCrU8ColorSpace::channels() const { + return m_channels; +} + +Q_UINT32 KisYCbCrU8ColorSpace::nChannels() const { + return MAX_CHANNEL_YCbCrA; +} + +Q_UINT32 KisYCbCrU8ColorSpace::nColorChannels() const { + return MAX_CHANNEL_YCbCr; +} + +Q_UINT32 KisYCbCrU8ColorSpace::pixelSize() const { + return MAX_CHANNEL_YCbCrA*sizeof(Q_UINT8); +} + + +QImage KisYCbCrU8ColorSpace::convertToQImage(const Q_UINT8 *data, Q_INT32 width, Q_INT32 height, KisProfile * dstProfile, Q_INT32 renderingIntent, float exposure ) +{ + if(getProfile()) + return KisU8BaseColorSpace::convertToQImage( data, width, height, dstProfile, renderingIntent, exposure); + + QImage img = QImage(width, height, 32, 0, QImage::LittleEndian); + img.setAlphaBuffer(true); + + Q_INT32 i = 0; + uchar *j = img.bits(); + + while ( i < width * height * MAX_CHANNEL_YCbCrA) { + Q_UINT8 Y = *( data + i + PIXEL_Y ); + Q_UINT8 Cb = *( data + i + PIXEL_Cb ); + Q_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(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *srcAlphaMask, Q_INT32 maskRowStride, Q_UINT8 opacity, Q_INT32 rows, Q_INT32 cols, const KisCompositeOp& op) +{ + switch (op.op()) { + case COMPOSITE_UNDEF: + // Undefined == no composition + break; + case COMPOSITE_OVER: + compositeOver(dst, dstRowStride, src, srcRowStride, srcAlphaMask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY: + compositeCopy(dst, dstRowStride, src, srcRowStride, srcAlphaMask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ERASE: + compositeErase(dst, dstRowStride, src, srcRowStride, srcAlphaMask, maskRowStride, rows, cols, opacity); + break; + default: + break; + } +} + +void KisYCbCrU8ColorSpace::compositeOver(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + while (rows > 0) { + + const Q_UINT8 *src = srcRowStart; + Q_UINT8 *dst = dstRowStart; + const Q_UINT8 *mask = maskRowStart; + Q_INT32 columns = numColumns; + + while (columns > 0) { + + Q_UINT8 srcAlpha = src[PIXEL_ALPHA]; + + // apply the alphamask + if (mask != 0) { + if (*mask != OPACITY_OPAQUE) { + srcAlpha *= *mask; + } + mask++; + } + + if (srcAlpha > OPACITY_TRANSPARENT) { + + if (opacity < OPACITY_OPAQUE) { + srcAlpha *= opacity; + } + + if (srcAlpha == OPACITY_OPAQUE) { + memcpy(dst, src, MAX_CHANNEL_YCbCrA * sizeof(Q_UINT8)); + } else { + Q_UINT8 dstAlpha = dst[PIXEL_ALPHA]; + + Q_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE ) { + srcBlend = srcAlpha; + } else { + Q_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(Q_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(maskRowStart) { + maskRowStart += maskRowStride; + } + } +} + +void KisYCbCrU8ColorSpace::compositeErase(Q_UINT8 *dst, Q_INT32 dstRowSize, const Q_UINT8 *src, Q_INT32 srcRowSize, const Q_UINT8 *srcAlphaMask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 cols, Q_UINT8 /*opacity*/) +{ + while (rows-- > 0) + { + const Pixel *s = reinterpret_cast(src); + Pixel *d = reinterpret_cast(dst); + const Q_UINT8 *mask = srcAlphaMask; + + for (Q_INT32 i = cols; i > 0; i--, s++, d++) + { + Q_UINT8 srcAlpha = s -> alpha; + + // apply the alphamask + if (mask != 0) { + if (*mask != OPACITY_OPAQUE) { + srcAlpha = *mask; + } + mask++; + } + d -> alpha = srcAlpha * d -> alpha; + } + + dst += dstRowSize; + src += srcRowSize; + if(srcAlphaMask) { + srcAlphaMask += maskRowStride; + } + } +} + +void KisYCbCrU8ColorSpace::compositeCopy(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 */*mask*/, Q_INT32 /*maskRowStride*/, Q_INT32 rows, Q_INT32 numColumns, Q_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/krita/colorspaces/ycbcr_u8/kis_ycbcr_u8_colorspace.h b/krita/colorspaces/ycbcr_u8/kis_ycbcr_u8_colorspace.h new file mode 100644 index 00000000..bc4d8329 --- /dev/null +++ b/krita/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* parent, KisProfile* p); + ~KisYCbCrU8ColorSpace(); + virtual bool willDegrade(ColorSpaceIndependence ) + { + return false; + }; + public: + void setPixel(Q_UINT8 *pixel, Q_UINT8 Y, Q_UINT8 Cb, Q_UINT8 Cr, Q_UINT8 alpha) const; + void getPixel(const Q_UINT8 *pixel, Q_UINT8 *Y, Q_UINT8 *Cb, Q_UINT8 *Cr, Q_UINT8 *alpha) const; + + virtual void fromQColor(const QColor& c, Q_UINT8 *dst, KisProfile * profile = 0); + virtual void fromQColor(const QColor& c, Q_UINT8 opacity, Q_UINT8 *dst, KisProfile * profile = 0); + + virtual void toQColor(const Q_UINT8 *src, QColor *c, KisProfile * profile = 0); + virtual void toQColor(const Q_UINT8 *src, QColor *c, Q_UINT8 *opacity, KisProfile * profile = 0); + + virtual Q_UINT8 difference(const Q_UINT8 *src1, const Q_UINT8 *src2); + virtual void mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const; + + virtual QValueVector channels() const; + virtual Q_UINT32 nChannels() const; + virtual Q_UINT32 nColorChannels() const; + virtual Q_UINT32 pixelSize() const; + + virtual QImage convertToQImage(const Q_UINT8 *data, Q_INT32 width, Q_INT32 height, + KisProfile * dstProfile, + Q_INT32 renderingIntent, + float exposure = 0.0f); + + virtual KisCompositeOpList userVisiblecompositeOps() const; + + protected: + + virtual void bitBlt(Q_UINT8 *dst, + Q_INT32 dstRowStride, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 *srcAlphaMask, + Q_INT32 maskRowStride, + Q_UINT8 opacity, + Q_INT32 rows, + Q_INT32 cols, + const KisCompositeOp& op); + + void compositeOver(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeErase(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + void compositeCopy(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity); + + private: +#define CLAMP_TO_8BITCHANNEL(a) CLAMP(a, 0, Q_UINT8_MAX) + inline Q_UINT8 computeRed(Q_UINT8 Y, Q_UINT8 /*Cb*/, Q_UINT8 Cr) + { + return (Q_UINT8)( CLAMP_TO_8BITCHANNEL( (Cr - 128)* (2-2*LUMA_RED) + Y ) ); + } + inline Q_UINT8 computeGreen(Q_UINT8 Y, Q_UINT8 Cb, Q_UINT8 Cr) + { + return (Q_UINT8)( CLAMP_TO_8BITCHANNEL( (Y - LUMA_BLUE * computeBlue(Y,Cb,Cr) - LUMA_RED * computeRed(Y,Cb,Cr) ) / LUMA_GREEN ) ); + } + inline Q_UINT8 computeBlue(Q_UINT8 Y, Q_UINT8 Cb, Q_UINT8 /*Cr*/) + { + return (Q_UINT8)( CLAMP_TO_8BITCHANNEL( (Cb - 128)*(2 - 2 * LUMA_BLUE) + Y) ); + } + inline Q_UINT8 computeY( Q_UINT8 r, Q_UINT8 b, Q_UINT8 g) + { + return (Q_UINT8)( CLAMP_TO_8BITCHANNEL( LUMA_RED*r + LUMA_GREEN*g + LUMA_BLUE*b ) ); + } + inline Q_UINT8 computeCb( Q_UINT8 r, Q_UINT8 b, Q_UINT8 g) + { + return (Q_UINT8)( CLAMP_TO_8BITCHANNEL( (b - computeY(r,g,b))/(2-2*LUMA_BLUE) + 128) ); + } + inline Q_UINT8 computeCr( Q_UINT8 r, Q_UINT8 b, Q_UINT8 g) + { + return (Q_UINT8)( CLAMP_TO_8BITCHANNEL( (r - computeY(r,g,b))/(2-2*LUMA_RED) + 128) ); + } +#undef CLAMP_TO_8BITCHANNEL + + static const Q_UINT8 PIXEL_Y = 0; + static const Q_UINT8 PIXEL_Cb = 1; + static const Q_UINT8 PIXEL_Cr = 2; + static const Q_UINT8 PIXEL_ALPHA = 3; + + struct Pixel { + Q_UINT8 Y; + Q_UINT8 Cb; + Q_UINT8 Cr; + Q_UINT8 alpha; + }; +}; + +class KisYCbCrU8ColorSpaceFactory : public KisColorSpaceFactory +{ + public: + /** + * Krita 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 Q_UINT32 colorSpaceType() { return TYPE_YCbCr_8; }; + + virtual icColorSpaceSignature colorSpaceSignature() { return icSigYCbCrData; }; + + virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) { return new KisYCbCrU8ColorSpace(parent, p); }; + + virtual QString defaultProfile() { return ""; }; +}; + +#endif diff --git a/krita/colorspaces/ycbcr_u8/krita_ycbcr_u8_plugin.desktop b/krita/colorspaces/ycbcr_u8/krita_ycbcr_u8_plugin.desktop new file mode 100644 index 00000000..2c29e972 --- /dev/null +++ b/krita/colorspaces/ycbcr_u8/krita_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=Krita/ColorSpace +Type=Service +X-KDE-Library=krita_ycbcr_u8_plugin +X-Krita-Version=2 diff --git a/krita/colorspaces/ycbcr_u8/ycbcr_u8_plugin.cc b/krita/colorspaces/ycbcr_u8/ycbcr_u8_plugin.cc new file mode 100644 index 00000000..751e3f31 --- /dev/null +++ b/krita/colorspaces/ycbcr_u8/ycbcr_u8_plugin.cc @@ -0,0 +1,62 @@ +/* + * ycbcr_u8_plugin.cc -- Part of Krita + * + * 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( krita_ycbcr_u8_plugin, YCbCrU8PluginFactory( "krita" ) ) + + +YCbCrU8Plugin::YCbCrU8Plugin(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(YCbCrU8PluginFactory::instance()); + + if ( parent->inherits("KisColorSpaceFactoryRegistry") ) + { + KisColorSpaceFactoryRegistry * f = dynamic_cast( parent ); + + 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/krita/colorspaces/ycbcr_u8/ycbcr_u8_plugin.h b/krita/colorspaces/ycbcr_u8/ycbcr_u8_plugin.h new file mode 100644 index 00000000..ef418784 --- /dev/null +++ b/krita/colorspaces/ycbcr_u8/ycbcr_u8_plugin.h @@ -0,0 +1,37 @@ +/* + * 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 +public: + YCbCrU8Plugin(QObject *parent, const char *name, const QStringList &); + virtual ~YCbCrU8Plugin(); + +}; + + +#endif // YCBCR_U8_PLUGIN_H_ diff --git a/krita/configure.in.bot b/krita/configure.in.bot new file mode 100644 index 00000000..40234694 --- /dev/null +++ b/krita/configure.in.bot @@ -0,0 +1,19 @@ +if test -z "$LCMS_LIBS"; then + echo "" + echo "LittleCMS is missing, Krita will not be built." + echo "" + echo "If you want to compile Krita 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 "not be able to use OpenGL for hardware" + echo "accelerated rendering." + echo "" + fi +fi + + diff --git a/krita/configure.in.in b/krita/configure.in.in new file mode 100644 index 00000000..2cb413b5 --- /dev/null +++ b/krita/configure.in.in @@ -0,0 +1,110 @@ +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 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 krita" +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" + +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 + +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/krita/core/Makefile.am b/krita/core/Makefile.am new file mode 100644 index 00000000..56a0865e --- /dev/null +++ b/krita/core/Makefile.am @@ -0,0 +1,59 @@ +# all_includes must remain last! +INCLUDES = \ + -I$(srcdir)/../sdk \ + -I$(srcdir)/tiles \ + -I$(srcdir)/../kritacolor \ + $(KOFFICE_INCLUDES) \ + $(KOPAINTER_INCLUDES) \ + $(OPENEXR_CFLAGS) \ + $(all_includes) + +#CXXFLAGS = -shared -fPIC + +lib_LTLIBRARIES = libkritaimage.la + +libkritaimage_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 + +libkritaimage_la_LDFLAGS = -version-info 1:0:0 -no-undefined $(all_libraries) +libkritaimage_la_LIBADD = ../sdk/libkritasdk.la ../kritacolor/libkritacolor.la tiles/libkritatile.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) + +libkritaimage_la_METASOURCES = AUTO + +KDE_OPTIONS = nofinal + diff --git a/krita/core/createdcop.py b/krita/core/createdcop.py new file mode 100755 index 00000000..b3395ea2 --- /dev/null +++ b/krita/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 * parent ); +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 * parent ) + : DCOPObject() +{ + m_parent = parent; +} + +""" + +def parseHeader(headerfile, classname): + # parse the source class header to get a list of functions we're going to wrap + functions = [] + if (headerfile.find("private:") > -1): + lines = headerfile[headerfile.find(classname):headerfile.find("private")].splitlines() + else: + lines = headerfile[headerfile.find(classname):headerfile.find("#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 slots:") or + line.find("~") != -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.find("{") > -1): + function = line[:line.find("{")] + if function.find("}") > -1: + function += line[line.find("}") + 1:] + complete = 1 + else: + i += 1 + # search for the missing } on the next lines + while i < len(lines): + if (lines[i].find("}") > -1): + function += lines[i][lines[i].find("}") + 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/krita/core/kis_adjustment_layer.cc b/krita/core/kis_adjustment_layer.cc new file mode 100644 index 00000000..873b24cf --- /dev/null +++ b/krita/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 QString &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, SIGNAL(sigSelectionChanged(KisImageSP)), + this, 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(), SIGNAL(sigSelectionChanged(KisImageSP)), + this, 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(Qt::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(); + + QRect bounds = extent(); + bounds |= image()->bounds(); + gc.fillRect(bounds, KisColor(Qt::white, cs), MIN_SELECTED); + gc.end(); +} + + +Q_INT32 KisAdjustmentLayer::x() const +{ + if (m_selection) + return m_selection->getX(); + else + return 0; +} + +void KisAdjustmentLayer::setX(Q_INT32 x) +{ + if (m_selection) { + m_selection->setX(x); + resetCache(); + } + +} + +Q_INT32 KisAdjustmentLayer::y() const +{ + if (m_selection) + return m_selection->getY(); + else + return 0; +} + +void KisAdjustmentLayer::setY(Q_INT32 y) +{ + if (m_selection) { + m_selection->setY(y); + resetCache(); + } +} + +QRect KisAdjustmentLayer::extent() const +{ + if (m_selection) + return m_selection->selectedRect(); + else if (image()) + return image()->bounds(); + else + return QRect(); +} + +QRect KisAdjustmentLayer::exactBounds() const +{ + if (m_selection) + return m_selection->selectedRect(); + else if (image()) + return image()->bounds(); + else + return QRect(); +} + +bool KisAdjustmentLayer::accept(KisLayerVisitor & v) +{ + return v.visit( this ); +} + +void KisAdjustmentLayer::paintSelection(QImage &img, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h) +{ + if (showSelection() && selection()) + selection()->paintSelection(img, x, y, w, h); +} + +void KisAdjustmentLayer::paintSelection(QImage &img, const QRect& scaledImageRect, const QSize& scaledImageSize, const QSize& imageSize) +{ + if (showSelection() && selection()) + selection()->paintSelection(img, scaledImageRect, scaledImageSize, imageSize); +} + +QImage KisAdjustmentLayer::createThumbnail(Q_INT32 w, Q_INT32 h) +{ + if (!selection()) + return QImage(); + + int srcw, srch; + if( image() ) + { + srcw = image()->width(); + srch = image()->height(); + } + else + { + const QRect e = extent(); + srcw = e.width(); + srch = e.height(); + } + + if (w > srcw) + { + w = srcw; + h = Q_INT32(double(srcw) / w * h); + } + if (h > srch) + { + h = srch; + w = Q_INT32(double(srch) / h * w); + } + + if (srcw > srch) + h = Q_INT32(double(srch) / srcw * w); + else if (srch > srcw) + w = Q_INT32(double(srcw) / srch * h); + + QColor c; + Q_UINT8 opacity; + QImage img(w,h,32); + + for (Q_INT32 y=0; y < h; ++y) { + Q_INT32 iY = (y * srch ) / h; + for (Q_INT32 x=0; x < w; ++x) { + Q_INT32 iX = (x * srcw ) / w; + m_selection->pixel(iX, iY, &c, &opacity); + img.setPixel(x, y, qRgb(opacity, opacity, opacity)); + } + } + + return img; +} + +void KisAdjustmentLayer::slotSelectionChanged(KisImageSP image) { + image->setModified(); +} + +#include "kis_adjustment_layer.moc" diff --git a/krita/core/kis_adjustment_layer.h b/krita/core/kis_adjustment_layer.h new file mode 100644 index 00000000..0137bc8f --- /dev/null +++ b/krita/core/kis_adjustment_layer.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., 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 QPainter; +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 + +public: + /** + * Create a new adjustment layer with the given configuration and selection. + * Note that the selection will be _copied_. + */ + KisAdjustmentLayer(KisImageSP img, const QString &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(QImage &img, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h); + virtual void paintSelection(QImage &img, const QRect& scaledImageRect, const QSize& scaledImageSize, const QSize& imageSize); +public: + + virtual Q_INT32 x() const; + virtual void setX(Q_INT32); + + virtual Q_INT32 y() const; + virtual void setY(Q_INT32); + + /// Returns an approximation of where the bounds on actual data are in this layer + virtual QRect extent() const; + + /// Returns the exact bounds of where the actual data resides in this layer + virtual QRect 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 QImage createThumbnail(Q_INT32 w, Q_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/krita/core/kis_alpha_mask.cc b/krita/core/kis_alpha_mask.cc new file mode 100644 index 00000000..7a0fcd81 --- /dev/null +++ b/krita/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 QImage& img, bool hasColor) +{ + m_width = img.width(); + m_height = img.height(); + + if (hasColor) { + copyAlpha(img); + } + else { + computeAlpha(img); + } +} + +KisAlphaMask::KisAlphaMask(const QImage& img) +{ + m_width = img.width(); + m_height = img.height(); + + if (!img.allGray()) { + copyAlpha(img); + } + else { + computeAlpha(img); + } +} + +KisAlphaMask::KisAlphaMask(Q_INT32 width, Q_INT32 height) +{ + m_width = width; + m_height = height; + + m_data.resize(width * height, OPACITY_TRANSPARENT); +} + +KisAlphaMask::~KisAlphaMask() +{ +} + +Q_INT32 KisAlphaMask::width() const +{ + return m_width; +} + +Q_INT32 KisAlphaMask::height() const +{ + return m_height; +} + +void KisAlphaMask::setAlphaAt(Q_INT32 x, Q_INT32 y, Q_UINT8 alpha) +{ + if (y >= 0 && y < m_height && x >= 0 && x < m_width) { + m_data[(y * m_width) + x] = alpha; + } +} + +void KisAlphaMask::copyAlpha(const QImage& img) +{ + for (int y = 0; y < img.height(); y++) { + for (int x = 0; x < img.width(); x++) { + QRgb c = img.pixel(x,y); + Q_UINT8 a = (qGray(c) * qAlpha(c)) / 255; + m_data.push_back(a); + + } + } +} + +void KisAlphaMask::computeAlpha(const QImage& 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 - qRed(img.pixel(x, y))); + } + } +} + +KisAlphaMaskSP KisAlphaMask::interpolate(KisAlphaMaskSP mask1, KisAlphaMaskSP mask2, double t) +{ + Q_ASSERT((mask1->width() == mask2->width()) && (mask1->height() == mask2->height())); + Q_ASSERT(t > -DBL_EPSILON && t < 1 + DBL_EPSILON); + + int width = mask1->width(); + int height = mask1->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++) { + Q_UINT8 d = static_cast((1 - t) * mask1->alphaAt(x, y) + t * mask2->alphaAt(x, y)); + outputMask->setAlphaAt(x, y, d); + } + } + + return outputMask; +} + + diff --git a/krita/core/kis_alpha_mask.h b/krita/core/kis_alpha_mask.h new file mode 100644 index 00000000..1da3384d --- /dev/null +++ b/krita/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 QImage for use + * in brush creation. It is not a generic alpha mask that can be used with + * KisPaintDevices: use a KisSelection for that. + */ +class KisAlphaMask : public KShared { + + public: + /** + Create an alpha mask based on the specified QImage. If the image is + not a grayscale, the mask value is calculated from the effective grey + level and alpha value. + */ + KisAlphaMask(const QImage& img); + + /** + As above except quicker as the image does not need to be scanned + to see if it has any colour pixels. + */ + KisAlphaMask(const QImage& img, bool hasColor); + + /** + Create a transparent mask. + */ + KisAlphaMask(Q_INT32 width, Q_INT32 height); + + virtual ~KisAlphaMask(); + + /** + @return the number of alpha values in a scanline. + */ + Q_INT32 height() const; + + /** + @return the number of lines in the mask. + */ + Q_INT32 width() const; + + /** + @return the alpha value at the specified position. + + Returns Q_UINT8 OPACITY_TRANSPARENT if the value is + outside the bounds of the mask. + + XXX: this is, of course, not the best way of masking. + Better would be to let KisAlphaMask fill a chunk of memory + with the alpha values at the right position, something like + void applyMask(Q_UINT8 *pixeldata, Q_INT32 pixelWidth, + Q_INT32 alphaPos). That would be fastest, or we could + provide an iterator over the mask, that would be nice, too. + */ + inline Q_UINT8 alphaAt(Q_INT32 x, Q_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(Q_INT32 x, Q_INT32 y, Q_UINT8 alpha); + + // Create a new mask by interpolating between mask1 and mask2 as t + // goes from 0 to 1. + static KisAlphaMaskSP interpolate(KisAlphaMaskSP mask1, KisAlphaMaskSP mask2, double t); + +private: + void computeAlpha(const QImage& img); + void copyAlpha(const QImage& img); + + QValueVector m_data; + Q_INT32 m_width; + Q_INT32 m_height; +}; + +#endif // KIS_ALPHA_MASK_ + diff --git a/krita/core/kis_autobrush_resource.cc b/krita/core/kis_autobrush_resource.cc new file mode 100644 index 00000000..6e45c64a --- /dev/null +++ b/krita/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( QImage* img) +{ + img->create(m_w, m_h, 32); + for(int j = 0; j < m_h; j++) + { + for(int i = 0; i < m_w; i++) + { + Q_INT8 v = valueAt(i,j); + img->setPixel( i, j, qRgb(v,v,v)); + } + } +} + +KisAutobrushCircleShape::KisAutobrushCircleShape(Q_INT32 w, Q_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)) +{ +} +Q_INT8 KisAutobrushCircleShape::valueAt(Q_INT32 x, Q_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(Q_INT32 w, Q_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) +{ +} +Q_INT8 KisAutobrushRectShape::valueAt(Q_INT32 x, Q_INT32 y) +{ + double xr = QABS(x - m_xcentre); + double yr = QABS(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/krita/core/kis_autobrush_resource.h b/krita/core/kis_autobrush_resource.h new file mode 100644 index 00000000..d0c77767 --- /dev/null +++ b/krita/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(Q_INT32 w, Q_INT32 h, double fh, double fv) : m_w(w), m_h(h), m_fh(fh), m_fv(fv) + { }; + void createBrush( QImage* img); + protected: + virtual Q_INT8 valueAt(Q_INT32 x, Q_INT32 y) =0; + Q_INT32 m_w, m_h; + double m_fh, m_fv; +}; + +class KisAutobrushCircleShape : public KisAutobrushShape { + public: + KisAutobrushCircleShape(Q_INT32 w, Q_INT32 h, double fh, double fv); + public: + virtual Q_INT8 valueAt(Q_INT32 x, Q_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(Q_INT32 w, Q_INT32 h, double fh, double fv); + protected: + virtual Q_INT8 valueAt(Q_INT32 x, Q_INT32 y); + private: + double m_xcentre, m_ycentre, m_c; +}; + +class KisAutobrushResource : public KisBrush +{ + public: + KisAutobrushResource(QImage& img) : KisBrush("") + { + setImage(img); + setBrushType(MASK); + }; + public: + virtual bool load() { return false; }; +}; +#endif // _KIS_AUTOBRUSH_RESOURCE_H_ diff --git a/krita/core/kis_autogradient_resource.cc b/krita/core/kis_autogradient_resource.cc new file mode 100644 index 00000000..f021222d --- /dev/null +++ b/krita/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, QColor left, QColor right ) +{ + pushSegment(new KisGradientSegment(interpolation, colorInterpolation, startOffset, middleOffset, endOffset, Color( left, 1 ), Color( right, 1 ))); + +} + +const QValueVector KisAutogradientResource::getHandlePositions() const +{ + QValueVector 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 QValueVector KisAutogradientResource::getMiddleHandlePositions() const +{ + QValueVector 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) +{ + QValueVector::iterator it = qFind( 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) +{ + QValueVector::iterator it = qFind( 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); + QValueVector::iterator it = qFind( 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); + QValueVector::iterator it = qFind( 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; + QValueVector::iterator it = qFind( 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/krita/core/kis_autogradient_resource.h b/krita/core/kis_autogradient_resource.h new file mode 100644 index 00000000..972ec8f6 --- /dev/null +++ b/krita/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, QColor left, QColor right ); + + const QValueVector getHandlePositions() const; + const QValueVector 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/krita/core/kis_background.cc b/krita/core/kis_background.cc new file mode 100644 index 00000000..8fff32ec --- /dev/null +++ b/krita/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 = QImage(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++) + { + Q_UINT8 v = 128 + 63 * ((x / 16 + y / 16) % 2); + m_patternTile.setPixel(x, y, qRgb(v, v, v)); + } + } +} + +KisBackground::~KisBackground() +{ +} + +const QImage& KisBackground::patternTile() const +{ + return m_patternTile; +} + +void KisBackground::paintBackground(QImage 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++) + { + QRgb *imagePixelPtr = reinterpret_cast(image.scanLine(y)); + const QRgb *patternScanLine = reinterpret_cast(m_patternTile.scanLine(patternY)); + int patternX = patternLeftX; + + for (int x = 0; x < imageWidth; x++) + { + QRgb imagePixel = *imagePixelPtr; + Q_UINT8 imagePixelAlpha = qAlpha(imagePixel); + + if (imagePixelAlpha != 255) { + + QRgb patternPixel = patternScanLine[patternX]; + Q_UINT8 imageRed = UINT8_BLEND(qRed(imagePixel), qRed(patternPixel), imagePixelAlpha); + Q_UINT8 imageGreen = UINT8_BLEND(qGreen(imagePixel), qGreen(patternPixel), imagePixelAlpha); + Q_UINT8 imageBlue = UINT8_BLEND(qBlue(imagePixel), qBlue(patternPixel), imagePixelAlpha); + + *imagePixelPtr = qRgba(imageRed, imageGreen, imageBlue, 255); + } + + ++imagePixelPtr; + ++patternX; + + if (patternX == PATTERN_WIDTH) { + patternX = 0; + } + } + + ++patternY; + + if (patternY == PATTERN_HEIGHT) { + patternY = 0; + } + } +} + +void KisBackground::paintBackground(QImage img, const QRect& scaledImageRect, const QSize& scaledImageSize, const QSize& imageSize) +{ + if (scaledImageRect.isEmpty() || scaledImageSize.isEmpty() || imageSize.isEmpty()) { + return; + } + + Q_ASSERT(img.size() == scaledImageRect.size()); + + if (img.size() != scaledImageRect.size()) { + return; + } + + Q_INT32 imageWidth = imageSize.width(); + Q_INT32 imageHeight = imageSize.height(); + + for (Q_INT32 y = 0; y < scaledImageRect.height(); ++y) { + + Q_INT32 scaledY = scaledImageRect.y() + y; + Q_INT32 srcY = (scaledY * imageHeight) / scaledImageSize.height(); + Q_INT32 patternY = srcY % PATTERN_HEIGHT; + + QRgb *imagePixelPtr = reinterpret_cast(img.scanLine(y)); + const QRgb *patternScanLine = reinterpret_cast(m_patternTile.scanLine(patternY)); + + for (Q_INT32 x = 0; x < scaledImageRect.width(); ++x) { + + QRgb imagePixel = *imagePixelPtr; + Q_UINT8 imagePixelAlpha = qAlpha(imagePixel); + + if (imagePixelAlpha != 255) { + + Q_INT32 scaledX = scaledImageRect.x() + x; + Q_INT32 srcX = (scaledX * imageWidth) / scaledImageSize.width(); + Q_INT32 patternX = srcX % PATTERN_WIDTH; + + QRgb patternPixel = patternScanLine[patternX]; + Q_UINT8 imageRed = UINT8_BLEND(qRed(imagePixel), qRed(patternPixel), imagePixelAlpha); + Q_UINT8 imageGreen = UINT8_BLEND(qGreen(imagePixel), qGreen(patternPixel), imagePixelAlpha); + Q_UINT8 imageBlue = UINT8_BLEND(qBlue(imagePixel), qBlue(patternPixel), imagePixelAlpha); + + *imagePixelPtr = qRgba(imageRed, imageGreen, imageBlue, 255); + } + + ++imagePixelPtr; + } + } +} + + diff --git a/krita/core/kis_background.h b/krita/core/kis_background.h new file mode 100644 index 00000000..59016ffb --- /dev/null +++ b/krita/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(QImage image, int leftX, int topY); + + void paintBackground(QImage image, const QRect& scaledImageRect, const QSize& scaledImageSize, const QSize& imageSize); + + // Returns the pattern tile. + const QImage& patternTile() const; + +protected: + static const int PATTERN_WIDTH = 32; + static const int PATTERN_HEIGHT = 32; + + QImage m_patternTile; +}; + +#endif // KIS_BACKGROUND_H_ + diff --git a/krita/core/kis_basic_math_toolbox.cpp b/krita/core/kis_basic_math_toolbox.cpp new file mode 100644 index 00000000..d20544af --- /dev/null +++ b/krita/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 QRect& 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 QRect& rect, KisWavelet* wav, KisWavelet* buff) +{ + if(buff == 0) + { + buff = initWavelet( dst, rect ); + } + + waveuntrans(wav, buff, 1 ); + transformFromFR(dst, wav, rect); +} diff --git a/krita/core/kis_basic_math_toolbox.h b/krita/core/kis_basic_math_toolbox.h new file mode 100644 index 00000000..ce80e55c --- /dev/null +++ b/krita/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 QRect&, KisWavelet* buff = 0); + virtual void fastWaveletUntransformation(KisPaintDeviceSP dst, const QRect&, 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/krita/core/kis_boundary.cc b/krita/core/kis_boundary.cc new file mode 100644 index 00000000..24524aeb --- /dev/null +++ b/krita/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(Q_UINT8 val) { + return val < m_fuzzyness; +} + +void KisBoundary::generateBoundary(int w, int h) { + if (!m_device) + return; + + KisColorSpace* cs = m_device->colorSpace(); + + // 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(QValueList()); + + while (!topIt.isDone()) { + darkTop = cs->getAlpha(topIt.rawData()); + darkBot = cs->getAlpha(botIt.rawData()); + if (darkTop != darkBot) { + // detected a change + m_horSegments.back().append(qMakePair(KisPoint(botIt.x(), botIt.y()), 1)); + } + ++topIt; + ++botIt; + } + } + + // 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(QValueList()); + + while (!leftIt.isDone()) { + darkLeft = cs->getAlpha(leftIt.rawData()); + darkRight = cs->getAlpha(rightIt.rawData()); + if (darkLeft != darkRight) { + // detected a change + m_vertSegments.back().append(qMakePair(KisPoint(rightIt.x(), rightIt.y()), 1)); + } + ++leftIt; + ++rightIt; + } + } +} + diff --git a/krita/core/kis_boundary.h b/krita/core/kis_boundary.h new file mode 100644 index 00000000..069d0289 --- /dev/null +++ b/krita/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 QPair PointPair; // int->length + bool isDark(Q_UINT8 val); + KisPaintDevice* m_device; + int m_fuzzyness; + + typedef QValueList PointPairList; + typedef QValueList< PointPairList > PointPairListList; + + PointPairListList m_horSegments; + PointPairListList m_vertSegments; + + friend class KisBoundaryPainter; +}; + +#endif // _KIS_BOUNDARY_H_ diff --git a/krita/core/kis_brush.cc b/krita/core/kis_brush.cc new file mode 100644 index 00000000..57ee2584 --- /dev/null +++ b/krita/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 { + Q_UINT32 header_size; /* header_size = sizeof (BrushHeader) + brush name */ + Q_UINT32 version; /* brush file version # */ + Q_UINT32 width; /* width of brush */ + Q_UINT32 height; /* height of brush */ + Q_UINT32 bytes; /* depth of brush in bytes */ + }; + + /// All fields are in MSB on disk! + struct GimpBrushHeader { + Q_UINT32 header_size; /* header_size = sizeof (BrushHeader) + brush name */ + Q_UINT32 version; /* brush file version # */ + Q_UINT32 width; /* width of brush */ + Q_UINT32 height; /* height of brush */ + Q_UINT32 bytes; /* depth of brush in bytes */ + + /* The following are only defined in version 2 */ + Q_UINT32 magic_number; /* GIMP brush magic number */ + Q_UINT32 spacing; /* brush spacing as % of width & height, 0 - 1000 */ + }; + + // Needed, or the GIMP won't open it! + Q_UINT32 const GimpV2BrushMagic = ('G' << 24) + ('I' << 16) + ('M' << 8) + ('P' << 0); +} + +#define DEFAULT_SPACING 0.25 +#define MAXIMUM_SCALE 2 + +KisBrush::KisBrush(const QString& 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 QString& filename, + const QByteArray& data, + Q_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(QString("")) +{ + 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 QImage& image, const QString& name) + : super(QString("")) +{ + 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) { + QFile 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; + } + + QString 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 = QString::fromAscii(text, bh.header_size - sizeof(GimpBrushV1Header)); + } else { + // ### Version = 3->cinepaint; may be float16 data! + // Version >=2: UTF-8 encoding is used + name = QString::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; + } + + Q_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 (Q_UINT32 y = 0; y < bh.height; y++) { + for (Q_UINT32 x = 0; x < bh.width; x++, k++) { + Q_INT32 val = 255 - static_cast(m_data[k]); + m_img.setPixel(x, y, qRgb(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 (Q_UINT32 y = 0; y < bh.height; y++) { + for (Q_UINT32 x = 0; x < bh.width; x++, k += 4) { + m_img.setPixel(x, y, qRgba(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->convertToQImage(0, x, y, w, h)); + setName(image->name()); + + m_brushType = IMAGE; + m_hasColor = true; + + return true; +} + +bool KisBrush::save() +{ + QFile file(filename()); + file.open(IO_WriteOnly | IO_Truncate); + bool ok = saveToDevice(&file); + file.close(); + return ok; +} + +bool KisBrush::saveToDevice(QIODevice* dev) const +{ + GimpBrushHeader bh; + QCString utf8Name = name().utf8(); // Names in v2 brushes are in UTF-8 + char const* name = utf8Name.data(); + int nameLength = qstrlen(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 + QByteArray 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 (Q_INT32 y = 0; y < height(); y++) { + for (Q_INT32 x = 0; x < width(); x++) { + QRgb c = m_img.pixel(x, y); + bytes[k++] = static_cast(255 - qRed(c)); // red == blue == green + } + } + } else { + bytes.resize(width() * height() * 4); + for (Q_INT32 y = 0; y < height(); y++) { + for (Q_INT32 x = 0; x < width(); x++) { + // order for gimp brushes, v2 is: RGBA + QRgb pixel = m_img.pixel(x,y); + bytes[k++] = static_cast(qRed(pixel)); + bytes[k++] = static_cast(qGreen(pixel)); + bytes[k++] = static_cast(qBlue(pixel)); + bytes[k++] = static_cast(qAlpha(pixel)); + } + } + } + + wrote = dev->writeBlock(bytes); + if (wrote == -1) + return false; + + return true; +} + +QImage KisBrush::img() +{ + QImage image = m_img; + + if (hasColor() && useColorAsMask()) { + image.detach(); + + for (int x = 0; x < image.width(); x++) { + for (int y = 0; y < image.height(); y++) { + QRgb c = image.pixel(x, y); + int a = (qGray(c) * qAlpha(c)) / 255; + image.setPixel(x, y, qRgba(a, 0, a, a)); + } + } + } + + return image; +} + +KisAlphaMaskSP KisBrush::mask(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 masks. 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 mask, which is always 1x1. + double s = scale / aboveBrush->scale(); + outputMask = scaleSinglePixelMask(s, aboveBrush->mask()->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); + + QImage outputImage; + + if (belowBrush != 0) { + // We're in between two brushes. Interpolate between them. + + QImage scaledAboveImage = scaleImage(aboveBrush, scale, subPixelX, subPixelY); + QImage 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++) { + Q_UINT8 * p = iter.rawData(); + + QRgb pixel = outputImage.pixel(x, y); + int red = qRed(pixel); + int green = qGreen(pixel); + int blue = qBlue(pixel); + int alpha = qAlpha(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; + + QImage 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 : QImage(), 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; +} + +Q_INT32 KisBrush::maskWidth(const KisPaintInformation& info) const +{ + // Add one for sub-pixel shift + return static_cast(ceil(width() * scaleForPressure(info.pressure)) + 1); +} + +Q_INT32 KisBrush::maskHeight(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->mask(); + + // 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; + + Q_UINT8 topLeft = (leftX >= 0 && leftX < srcWidth && topY >= 0 && topY < srcHeight) ? srcMask->alphaAt(leftX, topY) : OPACITY_TRANSPARENT; + Q_UINT8 bottomLeft = (leftX >= 0 && leftX < srcWidth && topY + 1 >= 0 && topY + 1 < srcHeight) ? srcMask->alphaAt(leftX, topY + 1) : OPACITY_TRANSPARENT; + Q_UINT8 topRight = (leftX + 1 >= 0 && leftX + 1 < srcWidth && topY >= 0 && topY < srcHeight) ? srcMask->alphaAt(leftX + 1, topY) : OPACITY_TRANSPARENT; + Q_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; +} + +QImage 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; + + QImage dstImage(dstWidth, dstHeight, 32); + dstImage.setAlphaBuffer(true); + + const QImage 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; + + QRgb topLeft = (leftX >= 0 && leftX < srcWidth && topY >= 0 && topY < srcHeight) ? srcImage.pixel(leftX, topY) : qRgba(0, 0, 0, 0); + QRgb bottomLeft = (leftX >= 0 && leftX < srcWidth && topY + 1 >= 0 && topY + 1 < srcHeight) ? srcImage.pixel(leftX, topY + 1) : qRgba(0, 0, 0, 0); + QRgb topRight = (leftX + 1 >= 0 && leftX + 1 < srcWidth && topY >= 0 && topY < srcHeight) ? srcImage.pixel(leftX + 1, topY) : qRgba(0, 0, 0, 0); + QRgb bottomRight = (leftX + 1 >= 0 && leftX + 1 < srcWidth && topY + 1 >= 0 && topY + 1 < srcHeight) ? srcImage.pixel(leftX + 1, topY + 1) : qRgba(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 * qRed(topLeft) + + a * (1 - b) * qRed(bottomLeft) + + (1 - a) * b * qRed(topRight) + + (1 - a) * (1 - b) * qRed(bottomRight) + 0.5); + int green = static_cast(a * b * qGreen(topLeft) + + a * (1 - b) * qGreen(bottomLeft) + + (1 - a) * b * qGreen(topRight) + + (1 - a) * (1 - b) * qGreen(bottomRight) + 0.5); + int blue = static_cast(a * b * qBlue(topLeft) + + a * (1 - b) * qBlue(bottomLeft) + + (1 - a) * b * qBlue(topRight) + + (1 - a) * (1 - b) * qBlue(bottomRight) + 0.5); + int alpha = static_cast(a * b * qAlpha(topLeft) + + a * (1 - b) * qAlpha(bottomLeft) + + (1 - a) * b * qAlpha(topRight) + + (1 - a) * (1 - b) * qAlpha(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, qRgba(red, green, blue, alpha)); + } + } + + return dstImage; +} + +QImage KisBrush::scaleImage(const QImage& srcImage, int width, int height) +{ + QImage scaledImage; + //QString 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 = QString("smoothScale_%1x%2.png").arg(width).arg(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; + + QRgb topLeft = (leftX >= 0 && leftX < srcWidth && topY >= 0 && topY < srcHeight) ? srcImage.pixel(leftX, topY) : qRgba(0, 0, 0, 0); + QRgb bottomLeft = (leftX >= 0 && leftX < srcWidth && topY + 1 >= 0 && topY + 1 < srcHeight) ? srcImage.pixel(leftX, topY + 1) : qRgba(0, 0, 0, 0); + QRgb topRight = (leftX + 1 >= 0 && leftX + 1 < srcWidth && topY >= 0 && topY < srcHeight) ? srcImage.pixel(leftX + 1, topY) : qRgba(0, 0, 0, 0); + QRgb bottomRight = (leftX + 1 >= 0 && leftX + 1 < srcWidth && topY + 1 >= 0 && topY + 1 < srcHeight) ? srcImage.pixel(leftX + 1, topY + 1) : qRgba(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 * qRed(topLeft) * qAlpha(topLeft) + + a * (1 - b) * qRed(bottomLeft) * qAlpha(bottomLeft) + + (1 - a) * b * qRed(topRight) * qAlpha(topRight) + + (1 - a) * (1 - b) * qRed(bottomRight) * qAlpha(bottomRight) + 0.5); + green = static_cast(a * b * qGreen(topLeft) * qAlpha(topLeft) + + a * (1 - b) * qGreen(bottomLeft) * qAlpha(bottomLeft) + + (1 - a) * b * qGreen(topRight) * qAlpha(topRight) + + (1 - a) * (1 - b) * qGreen(bottomRight) * qAlpha(bottomRight) + 0.5); + blue = static_cast(a * b * qBlue(topLeft) * qAlpha(topLeft) + + a * (1 - b) * qBlue(bottomLeft) * qAlpha(bottomLeft) + + (1 - a) * b * qBlue(topRight) * qAlpha(topRight) + + (1 - a) * (1 - b) * qBlue(bottomRight) * qAlpha(bottomRight) + 0.5); + alpha = static_cast(a * b * qAlpha(topLeft) + + a * (1 - b) * qAlpha(bottomLeft) + + (1 - a) * b * qAlpha(topRight) + + (1 - a) * (1 - b) * qAlpha(bottomRight) + 0.5); + + if (alpha != 0) { + red /= alpha; + green /= alpha; + blue /= alpha; + } + } + else { + red = static_cast(a * b * qRed(topLeft) + + a * (1 - b) * qRed(bottomLeft) + + (1 - a) * b * qRed(topRight) + + (1 - a) * (1 - b) * qRed(bottomRight) + 0.5); + green = static_cast(a * b * qGreen(topLeft) + + a * (1 - b) * qGreen(bottomLeft) + + (1 - a) * b * qGreen(topRight) + + (1 - a) * (1 - b) * qGreen(bottomRight) + 0.5); + blue = static_cast(a * b * qBlue(topLeft) + + a * (1 - b) * qBlue(bottomLeft) + + (1 - a) * b * qBlue(topRight) + + (1 - a) * (1 - b) * qBlue(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, qRgba(red, green, blue, alpha)); + } + } + + //filename = QString("bilinear_%1x%2.png").arg(width).arg(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, Q_UINT8 maskValue, 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++) { + + Q_UINT8 topLeft = (x > 0 && y > 0) ? maskValue : OPACITY_TRANSPARENT; + Q_UINT8 bottomLeft = (x > 0 && y < srcHeight) ? maskValue : OPACITY_TRANSPARENT; + Q_UINT8 topRight = (x < srcWidth && y > 0) ? maskValue : OPACITY_TRANSPARENT; + Q_UINT8 bottomRight = (x < srcWidth && y < srcHeight) ? maskValue : 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; +} + +QImage KisBrush::scaleSinglePixelImage(double scale, QRgb pixel, double subPixelX, double subPixelY) +{ + int srcWidth = 1; + int srcHeight = 1; + int dstWidth = 2; + int dstHeight = 2; + + QImage 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++) { + + QRgb topLeft = (x > 0 && y > 0) ? pixel : qRgba(0, 0, 0, 0); + QRgb bottomLeft = (x > 0 && y < srcHeight) ? pixel : qRgba(0, 0, 0, 0); + QRgb topRight = (x < srcWidth && y > 0) ? pixel : qRgba(0, 0, 0, 0); + QRgb bottomRight = (x < srcWidth && y < srcHeight) ? pixel : qRgba(0, 0, 0, 0); + + // Bi-linear interpolation. Images are in pre-multiplied form. + int red = static_cast(a * b * qRed(topLeft) + + a * (1 - b) * qRed(bottomLeft) + + (1 - a) * b * qRed(topRight) + + (1 - a) * (1 - b) * qRed(bottomRight) + 0.5); + int green = static_cast(a * b * qGreen(topLeft) + + a * (1 - b) * qGreen(bottomLeft) + + (1 - a) * b * qGreen(topRight) + + (1 - a) * (1 - b) * qGreen(bottomRight) + 0.5); + int blue = static_cast(a * b * qBlue(topLeft) + + a * (1 - b) * qBlue(bottomLeft) + + (1 - a) * b * qBlue(topRight) + + (1 - a) * (1 - b) * qBlue(bottomRight) + 0.5); + int alpha = static_cast(a * b * qAlpha(topLeft) + + a * (1 - b) * qAlpha(bottomLeft) + + (1 - a) * b * qAlpha(topRight) + + (1 - a) * (1 - b) * qAlpha(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, qRgba(red, green, blue, alpha)); + } + } + + return outputImage; +} + +QImage KisBrush::interpolate(const QImage& image1, const QImage& 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(); + + QImage outputImage(width, height, 32); + outputImage.setAlphaBuffer(true); + + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + QRgb image1pixel = image1.pixel(x, y); + QRgb image2pixel = image2.pixel(x, y); + + // Images are in pre-multiplied alpha format. + int red = static_cast((1 - t) * qRed(image1pixel) + t * qRed(image2pixel) + 0.5); + int green = static_cast((1 - t) * qGreen(image1pixel) + t * qGreen(image2pixel) + 0.5); + int blue = static_cast((1 - t) * qBlue(image1pixel) + t * qBlue(image2pixel) + 0.5); + int alpha = static_cast((1 - t) * qAlpha(image1pixel) + t * qAlpha(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, qRgba(red, green, blue, alpha)); + } + } + + return outputImage; +} + +KisBrush::ScaledBrush::ScaledBrush() +{ + m_mask = 0; + m_image = QImage(); + m_scale = 1; + m_xScale = 1; + m_yScale = 1; +} + +KisBrush::ScaledBrush::ScaledBrush(KisAlphaMaskSP scaledMask, const QImage& scaledImage, double scale, double xScale, double yScale) +{ + m_mask = 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++) { + + QRgb pixel = m_image.pixel(x, y); + + int red = qRed(pixel); + int green = qGreen(pixel); + int blue = qBlue(pixel); + int alpha = qAlpha(pixel); + + red = (red * alpha) / 255; + green = (green * alpha) / 255; + blue = (blue * alpha) / 255; + + m_image.setPixel(x, y, qRgba(red, green, blue, alpha)); + } + } + } +} + +void KisBrush::setImage(const QImage& img) +{ + m_img = img; + m_img.detach(); + + setWidth(img.width()); + setHeight(img.height()); + + m_scaledBrushes.clear(); + + setValid(true); +} + +Q_INT32 KisBrush::width() const +{ + return m_width; +} + +void KisBrush::setWidth(Q_INT32 w) +{ + m_width = w; +} + +Q_INT32 KisBrush::height() const +{ + return m_height; +} + +void KisBrush::setHeight(Q_INT32 h) +{ + m_height = h; +} + +/*QImage KisBrush::outline(double pressure) { + KisLayerSP layer = image(KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA",""),""), + KisPaintInformation(pressure)); + KisBoundary bounds(layer.data()); + int w = maskWidth(pressure); + int h = maskHeight(pressure); + + bounds.generateBoundary(w, h); + QPixmap pix(bounds.pixmap(w, h)); + QImage result; + result = pix; + return result; +}*/ + +void KisBrush::generateBoundary() { + KisPaintDeviceSP dev; + int w = maskWidth(KisPaintInformation()); + int h = maskHeight(KisPaintInformation()); + + if (brushType() == IMAGE || brushType() == PIPE_IMAGE) { + dev = image(KisMetaRegistry::instance()->csRegistry() ->getColorSpace(KisID("RGBA",""),""), KisPaintInformation()); + } else { + KisAlphaMaskSP amask = mask(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(), amask->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; + + QImage 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++) { + QRgb c = m_img.pixel(x, y); + int a = (qGray(c) * qAlpha(c)) / 255; // qGray(black) = 0 + img.setPixel(x, y, qRgba(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/krita/core/kis_brush.h b/krita/core/kis_brush.h new file mode 100644 index 00000000..7de2c8b7 --- /dev/null +++ b/krita/core/kis_brush.h @@ -0,0 +1,191 @@ +/* + * 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 QPoint; +class QPixmap; +class KisBoundary; +class KisColorSpace; +class QIODevice; + +enum enumBrushType { + INVALID, + MASK, + IMAGE, + PIPE_MASK, + PIPE_IMAGE, + AIRBRUSH +}; + +class KRITACORE_EXPORT KisBrush : public KisResource { + typedef KisResource super; + Q_OBJECT + +public: + /// Construct brush to load filename later as brush + KisBrush(const QString& filename); + /// Load brush from the specified data, at position dataPos, and set the filename + KisBrush(const QString& filename, + const QByteArray & data, + Q_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 QImage (handy when you need to copy a brush!) + KisBrush(const QImage& image, const QString& name = QString("")); + + virtual ~KisBrush(); + + virtual bool load(); + /// synchronous, doesn't emit any signal (none defined!) + virtual bool save(); + virtual QImage img(); + virtual bool saveToDevice(QIODevice* dev) const; + + /** + @return a mask computed from the grey-level values of the + pixels in the brush. + */ + virtual KisAlphaMaskSP mask(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 mask/image at a given pressure. + Q_INT32 maskWidth(const KisPaintInformation& info) const; + Q_INT32 maskHeight(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(); + Q_INT32 width() const; + Q_INT32 height() const; + + virtual enumBrushType brushType() const; + + //QImage 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(Q_INT32 w); + void setHeight(Q_INT32 h); + void setImage(const QImage& img); + void setBrushType(enumBrushType type) { m_brushType = type; }; + static double scaleForPressure(double pressure); + +private: + class ScaledBrush { + public: + ScaledBrush(); + ScaledBrush(KisAlphaMaskSP scaledMask, const QImage& 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 mask() const { return m_mask; } + QImage image() const { return m_image; } + + private: + KisAlphaMaskSP m_mask; + QImage 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; + QImage scaleImage(const ScaledBrush *srcBrush, double scale, double subPixelX, double subPixelY) const; + + static QImage scaleImage(const QImage& srcImage, int width, int height); + static QImage interpolate(const QImage& image1, const QImage& image2, double t); + + static KisAlphaMaskSP scaleSinglePixelMask(double scale, Q_UINT8 maskValue, double subPixelX, double subPixelY); + static QImage scaleSinglePixelImage(double scale, QRgb 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(); + + QByteArray m_data; + bool m_ownData; + KisPoint m_hotSpot; + double m_spacing; + bool m_useColorAsMask; + bool m_hasColor; + QImage m_img; + mutable QValueVector m_scaledBrushes; + + Q_INT32 m_width; + Q_INT32 m_height; + + Q_UINT32 m_header_size; /* header_size = sizeof (BrushHeader) + brush name */ + Q_UINT32 m_version; /* brush file version # */ + Q_UINT32 m_bytes; /* depth of brush in bytes */ + Q_UINT32 m_magic_number; /* GIMP brush magic number */ + + enumBrushType m_brushType; + + KisBoundary* m_boundary; + +}; +#endif // KIS_BRUSH_ + diff --git a/krita/core/kis_change_profile_visitor.h b/krita/core/kis_change_profile_visitor.h new file mode 100644 index 00000000..dea0eb4b --- /dev/null +++ b/krita/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/krita/core/kis_colorspace_convert_visitor.h b/krita/core/kis_colorspace_convert_visitor.h new file mode 100644 index 00000000..ce4ee787 --- /dev/null +++ b/krita/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, Q_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; + Q_INT32 m_renderingIntent; +}; + +KisColorSpaceConvertVisitor::KisColorSpaceConvertVisitor(KisColorSpace *dstColorSpace, Q_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/krita/core/kis_command.cc b/krita/core/kis_command.cc new file mode 100644 index 00000000..bcc997ea --- /dev/null +++ b/krita/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 QString& name, KisUndoAdapter *adapter) +{ + m_name = name; + m_undoAdapter = adapter; +} + +KisCommand::~KisCommand() +{ +} + +QString KisCommand::name() const +{ + return m_name; +} + diff --git a/krita/core/kis_command.h b/krita/core/kis_command.h new file mode 100644 index 00000000..f391c087 --- /dev/null +++ b/krita/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 QString& name, KisUndoAdapter *undoAdapter); + virtual ~KisCommand(); + + virtual void execute() = 0; + virtual void unexecute() = 0; + virtual QString name() const; + +protected: + KisUndoAdapter *adapter() const; + +private: + KisUndoAdapter *m_undoAdapter; + QString m_name; +}; + +inline +KisUndoAdapter *KisCommand::adapter() const +{ + return m_undoAdapter; +} + +#endif // KIS_COMMAND_H_ + diff --git a/krita/core/kis_convolution_painter.cc b/krita/core/kis_convolution_painter.cc new file mode 100644 index 00000000..cb51480c --- /dev/null +++ b/krita/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 "qbrush.h" +#include "qcolor.h" +#include "qfontinfo.h" +#include "qfontmetrics.h" +#include "qpen.h" +#include "qregion.h" +#include "qwmatrix.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::fromQImage(const QImage& 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 Q_INT32[count]; + Q_INT32* itData = k->data; + Q_UINT8* itImg = 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, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h, + KisConvolutionBorderOp borderOp, + KisChannelInfo::enumChannelFlags channelFlags ) +{ + // Make the area we cover as small as possible + if (m_device->hasSelection()) { + + QRect r = m_device->selection()->selectedRect().intersect(QRect(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 + Q_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(); + Q_UINT8** pixelPtrCache = new Q_UINT8*[cacheSize]; + for (int i = 0; i < cacheSize; i++) + pixelPtrCache[i] = new Q_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) + { + Q_INT32 i = 0; + for (Q_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 (Q_INT32 krow = 0; krow < kh; ++krow) { // shift the cache to the left + Q_UINT8** d = pixelPtrCache + krow * kw; + //memmove( d, d + 1, (kw-1)*sizeof(Q_UINT8*)); + for (int i = 0; i < (kw-1); i++) { + memcpy(d[i], d[i+1], cdepth); + } + } + Q_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(QRect(x, y, w, h)); + + emit notifyProgressDone(); + + for (int i = 0; i < cacheSize; i++) + delete[] pixelPtrCache[i]; + delete[] pixelPtrCache; +} + +void KisConvolutionPainter::applyMatrixRepeat(KisKernelSP kernel, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h, + KisChannelInfo::enumChannelFlags channelFlags) +{ + int lastProgressPercent = 0; + // Determine the kernel's extent from the center pixel + Q_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(); + Q_UINT8** pixelPtrCache = new Q_UINT8*[cacheSize]; + for (int i = 0; i < cacheSize; i++) + pixelPtrCache[i] = new Q_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; + + Q_INT32 itStart = row - khalfHeight; + Q_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 + { + Q_INT32 i = 0; + Q_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 + Q_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; + } + Q_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 + Q_INT32 itHStart = col - khalfWidth; + Q_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; + } + } + Q_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 (Q_INT32 krow = 0; krow < kh; ++krow) { // shift the cache to the left + Q_UINT8** d = pixelPtrCache + krow * kw; +// memmove( d, d + 1, (kw-1)*sizeof(Q_UINT8*)); + for (int i = 0; i < (kw-1); i++) { + memcpy(d[i], d[i+1], cdepth); + } + }*/ + Q_UINT8* firstincache = pixelPtrCache[0]; + memmove(pixelPtrCache, pixelPtrCache + 1, (cacheSize - 1) * sizeof(Q_UINT8*) ); + pixelPtrCache[cacheSize - 1] = firstincache; + if(col < xLastMinuskhw) + { + Q_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; + } + Q_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(QRect(x, y, w, h)); + + emit notifyProgressDone(); + for (int i = 0; i < cacheSize; i++) + delete[] pixelPtrCache[i]; + delete[] pixelPtrCache; +} diff --git a/krita/core/kis_convolution_painter.h b/krita/core/kis_convolution_painter.h new file mode 100644 index 00000000..d4aa8efb --- /dev/null +++ b/krita/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: + + Q_UINT32 width; + Q_UINT32 height; + Q_INT32 offset; + Q_INT32 factor; + Q_INT32 * data; + + KisKernel() : width(0), height(0), offset(0), factor(0), data(0) {}; + + virtual ~KisKernel() { delete [] data; }; + + static KisKernelSP fromQImage(const QImage& 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, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_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, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h, + KisChannelInfo::enumChannelFlags channelFlags); + + +}; +#endif //KIS_CONVOLUTION_PAINTER_H_ diff --git a/krita/core/kis_crop_visitor.h b/krita/core/kis_crop_visitor.h new file mode 100644 index 00000000..6e5c826c --- /dev/null +++ b/krita/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 "qrect.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 QRect & 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: + QRect m_rect; + bool m_movelayers; +}; + + +#endif diff --git a/krita/core/kis_datamanager.h b/krita/core/kis_datamanager.h new file mode 100644 index 00000000..2c450004 --- /dev/null +++ b/krita/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 Q_UINT8's a single pixel takes. + */ +class KisDataManager : public ACTUAL_DATAMGR { + +public: + KisDataManager(Q_UINT32 pixelSize, const Q_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 Q_UINT8 *defPixel) { return ACTUAL_DATAMGR::setDefaultPixel(defPixel); } + + /** + * Gets the default pixel. + */ + inline const Q_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 Q_UINT32 pixelSize() { return ACTUAL_DATAMGR::pixelSize(); } + + /** + * Return the extent of the data in x,y,w,h. + */ + inline void extent(Q_INT32 &x, Q_INT32 &y, Q_INT32 &w, Q_INT32 &h) const + { return ACTUAL_DATAMGR::extent(x, y, w, h); } + + QRect extent() const { return ACTUAL_DATAMGR::extent(); } + + +public: + + /** + * Crop or extend the data to x, y, w, h. + */ + inline void setExtent(Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h) + { return ACTUAL_DATAMGR::setExtent(x, y, w, h); } + + inline void setExtent(const QRect & rect) { setExtent(rect.x(), rect.y(), rect.width(), rect.height()); } + +public: + + /** + * Clear the specified rect to the specified value. + */ + inline void clear(Q_INT32 x, Q_INT32 y, + Q_INT32 w, Q_INT32 h, + Q_UINT8 def) { ACTUAL_DATAMGR::clear(x, y, w, h, def); } + + /** + * Clear the specified rect to the specified pixel value. + */ + inline void clear(Q_INT32 x, Q_INT32 y, + Q_INT32 w, Q_INT32 h, + const Q_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, Q_INT32 sx, Q_INT32 sy, Q_INT32 dx, Q_INT32 dy, + Q_INT32 w, Q_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 Q_UINT8* pixel(Q_INT32 x, Q_INT32 y) + { return ACTUAL_DATAMGR::pixel(x, y); } + + /** + * Get a read-write pointer to the specified pixel. + */ + inline KDE_DEPRECATED Q_UINT8* writablePixel(Q_INT32 x, Q_INT32 y) + { return ACTUAL_DATAMGR::writablePixel(x, y); } + + /** + * Write the specified data to x, y. There is no checking on pixelSize! + */ + inline void setPixel(Q_INT32 x, Q_INT32 y, const Q_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 QValueVector? + */ + inline void readBytes(Q_UINT8 * data, + Q_INT32 x, Q_INT32 y, + Q_INT32 w, Q_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 QValueVector? + */ + inline void writeBytes(const Q_UINT8 * data, + Q_INT32 x, Q_INT32 y, + Q_INT32 w, Q_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 Q_INT32 numContiguousColumns(Q_INT32 x, Q_INT32 minY, Q_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 Q_INT32 numContiguousRows(Q_INT32 y, Q_INT32 minX, Q_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 Q_INT32 rowStride(Q_INT32 x, Q_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/krita/core/kis_exif_info.cc b/krita/core/kis_exif_info.cc new file mode 100644 index 00000000..f81a1566 --- /dev/null +++ b/krita/core/kis_exif_info.cc @@ -0,0 +1,66 @@ +/* + * This file is part of Krita + * + * 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 QDomElement& elmt) +{ + if(elmt.tagName() != "ExifInfo") + return false; + for( QDomNode node = elmt.firstChild(); !node.isNull(); node = node.nextSibling() ) + { + QDomElement e = node.toElement(); + if ( !e.isNull() ) + { + if(e.tagName() == "ExifValue") + { + QString key = e.attribute("name"); + ExifValue eV; + eV.load(e); + setValue(key, eV); + } + } + } + return true; +} + +QDomElement KisExifInfo::save(QDomDocument& doc) +{ + QDomElement elmt = doc.createElement("ExifInfo"); + for( KisExifInfo::evMap::const_iterator it = begin(); it != end(); ++it) + { + ExifValue ev = it.data(); + QDomElement evD = ev.save( doc); + evD.setAttribute("name", it.key()); + elmt.appendChild(evD); + } + return elmt; +} diff --git a/krita/core/kis_exif_info.h b/krita/core/kis_exif_info.h new file mode 100644 index 00000000..aaebf3a9 --- /dev/null +++ b/krita/core/kis_exif_info.h @@ -0,0 +1,58 @@ +/* + * This file is part of Krita + * + * 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 QDomElement& elmt); + virtual QDomElement save(QDomDocument& doc); + + bool getValue(QString name, ExifValue& value) + { + if ( m_values.find( name ) == m_values.end() ) { + return false; + } + else { + value = m_values[name]; + return true; + } + } + void setValue(QString name, ExifValue value) + { + m_values[name] = value; + } + typedef QMap 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/krita/core/kis_exif_value.cc b/krita/core/kis_exif_value.cc new file mode 100644 index 00000000..25e78208 --- /dev/null +++ b/krita/core/kis_exif_value.cc @@ -0,0 +1,678 @@ +/* + * This file is part of Krita + * + * 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 Q_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, Q_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, Q_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 Q_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, Q_UINT64* value) +{ + switch (order) { + case ExifValue::BYTE_ORDER_MOTOROLA: + *value = (((Q_UINT64)data[0] << 56) | ((Q_UINT64)data[1] << 48) | ((Q_UINT64)data[2] << 40) | ((Q_UINT64)data[3] << 32) | ((Q_UINT64)data[4] << 24) | ((Q_UINT64)data[5] << 16) | ((Q_UINT64)data[6] << 8) | (Q_UINT64)data[7]); + break; + case ExifValue::BYTE_ORDER_INTEL: + *value = (((Q_UINT64)data[7] << 56) | ((Q_UINT64)data[6] << 48) | ((Q_UINT64)data[5] << 40) | ((Q_UINT64)data[4] << 32) | ((Q_UINT64)data[3] << 24) | ((Q_UINT64)data[2] << 16) | ((Q_UINT64)data[1] << 8) | (Q_UINT64)data[0]); + } +} + +void set64Bit(unsigned char *data, ExifValue::ByteOrder order, const Q_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 QString(); + } else if ( type() == EXIF_TYPE_UNDEFINED) + { + m_value = new UByteArray(); + } +} + +bool ExifValue::load(const QDomElement& elmt) +{ + QString 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(QString("value%1").arg(i) ) ).isNull() ) + { + setValue(i, (Q_UINT8)0); + } else { + setValue(i, (Q_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(QString("value%1").arg(i) ) ).isNull() ) + { + setValue(i, (Q_UINT16)0); + } else { + setValue(i, (Q_UINT16) attr.toUInt()); + } + } + break; + case EXIF_TYPE_LONG: + for(uint i = 0; i < components(); i++) + { + if( (attr = elmt.attribute(QString("value%1").arg(i) ) ).isNull() ) + { + setValue(i, (Q_UINT32)0); + } else { + setValue(i, (Q_UINT32) attr.toUInt()); + } + } + break; + case EXIF_TYPE_RATIONAL: + for(uint i = 0; i < components(); i++) + { + KisExifRational r; + if( (attr = elmt.attribute(QString("numerator%1").arg(i) ) ).isNull() ) + { + r.numerator = (Q_UINT32)0; + } else { + r.numerator = (Q_UINT32) attr.toUInt(); + } + if( (attr = elmt.attribute(QString("denominator%1").arg(i) ) ).isNull() ) + { + r.denominator = (Q_UINT32)0; + } else { + r.denominator = (Q_UINT32) attr.toUInt(); + } + setValue(i, r); + } + break; + case EXIF_TYPE_SBYTE: + for(uint i = 0; i < components(); i++) + { + if( (attr = elmt.attribute(QString("value%1").arg(i) ) ).isNull() ) + { + setValue(i, (Q_INT8)0); + } else { + setValue(i, (Q_INT8) attr.toInt()); + } + } + break; + case EXIF_TYPE_UNDEFINED: + { + QString instr = elmt.attribute("value"); + QByteArray out; + QByteArray 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(QString("value%1").arg(i) ) ).isNull() ) + { + setValue(i, (Q_INT16)0); + } else { + setValue(i, (Q_INT16) attr.toInt()); + } + } + break; + case EXIF_TYPE_SLONG: + for(uint i = 0; i < components(); i++) + { + if( (attr = elmt.attribute(QString("value%1").arg(i) ) ).isNull() ) + { + setValue(i, (Q_INT32)0); + } else { + setValue(i, (Q_INT32) attr.toInt()); + } + } + break; + case EXIF_TYPE_SRATIONAL: + for(uint i = 0; i < components(); i++) + { + KisExifSRational r; + if( (attr = elmt.attribute(QString("numerator%1").arg(i) ) ).isNull() ) + { + r.numerator = (Q_INT32)0; + } else { + r.numerator = (Q_INT32) attr.toInt(); + } + if( (attr = elmt.attribute(QString("denominator%1").arg(i) ) ).isNull() ) + { + r.denominator = (Q_UINT32)0; + } else { + r.denominator = (Q_UINT32) attr.toInt(); + } + setValue(i, r); + } + break; + case EXIF_TYPE_FLOAT: + for(uint i = 0; i < components(); i++) + { + if( (attr = elmt.attribute(QString("value%1").arg(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(QString("value%1").arg(i) ) ).isNull() ) + { + setValue(i, (double)0); + } else { + setValue(i, (double) attr.toDouble()); + } + } + break; + case EXIF_TYPE_UNKNOW: + break; + + } + return true; +} + +QDomElement ExifValue::save(QDomDocument& doc) +{ + QDomElement 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(QString("value%1").arg(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(QString("value%1").arg(i), asShort( i ) ); + break; + case EXIF_TYPE_LONG: + for(uint i = 0; i < components(); i++) + elmt.setAttribute(QString("value%1").arg(i), asLong( i ) ); + break; + case EXIF_TYPE_RATIONAL: + for(uint i = 0; i < components(); i++) + { + KisExifRational r = asRational(i); + elmt.setAttribute(QString("numerator%1").arg(i), r.numerator ); + elmt.setAttribute(QString("denominator%1").arg(i), r.denominator ); + } + break; + case EXIF_TYPE_SBYTE: + for(uint i = 0; i < components(); i++) + elmt.setAttribute(QString("value%1").arg(i), asSByte( i ) ); + break; + case EXIF_TYPE_UNDEFINED: + { + UByteArray value = asUndefined(); + QByteArray data; + data.setRawData((char*)value.data(), value.size()); + QByteArray encodedData; + KCodecs::base64Encode( data, encodedData ); + data.resetRawData( (char*)value.data(), value.size()); + elmt.setAttribute("value", encodedData); + } + break; + case EXIF_TYPE_SSHORT: + for(uint i = 0; i < components(); i++) + elmt.setAttribute(QString("value%1").arg(i), asSShort( i ) ); + break; + case EXIF_TYPE_SLONG: + for(uint i = 0; i < components(); i++) + elmt.setAttribute(QString("value%1").arg(i), asSLong( i ) ); + break; + case EXIF_TYPE_SRATIONAL: + for(uint i = 0; i < components(); i++) + { + KisExifSRational r = asSRational(i); + elmt.setAttribute(QString("numerator%1").arg(i), r.numerator ); + elmt.setAttribute(QString("denominator%1").arg(i), r.denominator ); + } + break; + case EXIF_TYPE_FLOAT: + for(uint i = 0; i < components(); i++) + elmt.setAttribute(QString("value%1").arg(i), asFloat( i ) ); + break; + case EXIF_TYPE_DOUBLE: + for(uint i = 0; i < components(); i++) + elmt.setAttribute(QString("value%1").arg(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 = ((Q_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, (Q_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, (Q_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, (Q_UINT32*)&n.m_srational.numerator); + get32Bit( data + 8 * i + 4, order, (Q_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, (Q_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, (Q_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: + { + QString 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++) + { + *(((Q_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, (Q_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, (Q_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, (Q_UINT32*)&asExifNumber(i).m_srational.numerator); + set32Bit( (*data) + 4 * i + 4, order, (Q_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, (Q_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, (Q_UINT64*)&asExifNumber(i).m_double); + } + return; + case EXIF_TYPE_UNKNOW: + break; + } +} + +QString ExifValue::toString() +{ + switch(type()) + { + case EXIF_TYPE_ASCII: + return asAscii(); + case EXIF_TYPE_UNDEFINED: + { + QString undefined = "undefined"; + UByteArray array = asUndefined(); + for(uint i = 0; i < components(); i++) + { + undefined += "\\" + QString().setNum( array[i] ); + } + return undefined; + } + default: + { + QString str = ""; + for(uint i = 0; i < components(); i++) + { + str += toString(i); + } + return str; + } + } +} + +QString ExifValue::toString(uint i) +{ + switch(type()) + { + case EXIF_TYPE_BYTE: + return QString("%1 ").arg( asExifNumber( i ).m_byte ); + case EXIF_TYPE_SHORT: + return QString("%1 ").arg( asExifNumber( i ).m_short ); + case EXIF_TYPE_LONG: + return QString("%1 ").arg( asExifNumber( i ).m_long ); + case EXIF_TYPE_RATIONAL: + return QString("%1 / %2 ").arg( asExifNumber( i ).m_rational.numerator ).arg( asExifNumber( i ).m_rational.denominator ); + case EXIF_TYPE_SBYTE: + return QString("%1 ").arg( asExifNumber( i ).m_sbyte ); + case EXIF_TYPE_SSHORT: + return QString("%1 ").arg( asExifNumber( i ).m_sshort ); + case EXIF_TYPE_SLONG: + return QString("%1 ").arg( asExifNumber( i ).m_slong ); + case EXIF_TYPE_SRATIONAL: + return QString("%1 / %2 ").arg( asExifNumber( i ).m_srational.numerator ).arg( asExifNumber( i ).m_srational.denominator ); + case EXIF_TYPE_FLOAT: + return QString("%1 ").arg( asExifNumber( i ).m_float ); + case EXIF_TYPE_DOUBLE: + return QString("%1 ").arg( asExifNumber( i ).m_double ); + default: + return "unknow "; + } +} + diff --git a/krita/core/kis_exif_value.h b/krita/core/kis_exif_value.h new file mode 100644 index 00000000..6e37e0a3 --- /dev/null +++ b/krita/core/kis_exif_value.h @@ -0,0 +1,270 @@ +/* + * This file is part of Krita + * + * 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 QMemArray UByteArray; + +struct KisExifRational { + Q_UINT32 numerator; + Q_UINT32 denominator; +}; + +struct KisExifSRational { + Q_INT32 numerator; + Q_INT32 denominator; +}; + +class ExifValue { + typedef union { + Q_UINT8 m_byte; + Q_UINT16 m_short; + Q_UINT32 m_long; + KisExifRational m_rational; + Q_INT8 m_sbyte; + Q_INT16 m_sshort; + Q_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 QDomElement& elmt); + virtual QDomElement save(QDomDocument& 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 QString asAscii() { + if(m_type == EXIF_TYPE_ASCII) + return QString(*(QString*) m_value); + return QString(); + } + inline void setAsAscii(char* data) + { + if(m_type == EXIF_TYPE_ASCII) + { + QString str = QString((char*) data); + *(QString*)m_value = str; + m_components = str.length(); + } + } + inline void setAsAscii(QString str) + { + *(QString*)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. + */ + QString toString(); + + inline Q_UINT8 asByte(uint i) + { + if(m_type == EXIF_TYPE_BYTE) + return asExifNumber(i).m_byte; + return 0; + } + inline void setValue(uint i, Q_UINT8 v) + { + ((ExifNumber*)m_value)[i].m_byte = v; + } + inline Q_UINT8 asShort(uint i) + { + if(m_type == EXIF_TYPE_SHORT) + return asExifNumber(i).m_short; + return 0; + } + inline void setValue(uint i, Q_UINT16 v) + { + ((ExifNumber*)m_value)[i].m_short = v; + } + inline Q_UINT8 asLong(uint i) + { + if(m_type == EXIF_TYPE_LONG) + return asExifNumber(i).m_long; + return 0; + } + inline void setValue(uint i, Q_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, Q_UINT32 n, Q_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 Q_INT8 asSByte(uint i) + { + if(m_type == EXIF_TYPE_SBYTE) + return asExifNumber(i).m_sbyte; + return 0; + } + inline void setValue(uint i, Q_INT8 v) + { + ((ExifNumber*)m_value)[i].m_sbyte = v; + } + inline Q_INT16 asSShort(uint i) + { + if(m_type == EXIF_TYPE_SSHORT) + return asExifNumber(i).m_sshort; + return 0; + } + inline void setValue(uint i, Q_INT16 v) + { + ((ExifNumber*)m_value)[i].m_sshort = v; + } + inline Q_INT32 asSLong(uint i) + { + if(m_type == EXIF_TYPE_SLONG) + return asExifNumber(i).m_slong; + return 0; + } + inline void setValue(uint i, Q_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, Q_INT32 n, Q_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. + */ + QString 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/krita/core/kis_fill_painter.cc b/krita/core/kis_fill_painter.cc new file mode 100644 index 00000000..0ccb9e8a --- /dev/null +++ b/krita/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 "qbrush.h" +#include "qfontinfo.h" +#include "qfontmetrics.h" +#include "qpen.h" +#include "qregion.h" +#include "qwmatrix.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(Q_INT32 x1, Q_INT32 y1, Q_INT32 w, Q_INT32 h, const KisColor& kc, Q_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()); + Q_UINT8 * data = kc2.data(); + m_device->colorSpace()->setAlpha(data, opacity, 1); + + m_device->fill(x1, y1, w, h, data); + + addDirtyRect(QRect(x1, y1, w, h)); + } +} + +void KisFillPainter::fillRect(Q_INT32 x1, Q_INT32 y1, Q_INT32 w, Q_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 = QMIN((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 = QMIN((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(QRect(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; + } + + QRect 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* parent*/) : x(x), y(y)/*, parent(parent)*/ {} + int x; + int y; +// FillSegment* parent; +}; + +typedef enum { None = 0, Added = 1, Checked = 2 } Status; + +KisSelectionSP KisFillPainter::createFloodSelection(int startX, int startY) { + if (m_width < 0 || m_height < 0) { + if (m_device->hasSelection() && m_careForSelection) { + + QRect 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(); + + Q_UINT8* source = new Q_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*/)); + + Status* map = new Status[m_size]; + + memset(map, None, m_size * sizeof(Status)); + + 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; + Q_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->fromQColor(Qt::white, MAX_SELECTED - diff, selIt.rawData()); + else + colorSpace->fromQColor(Qt::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->fromQColor(Qt::white, MAX_SELECTED - diff, selIt.rawData()); + else + colorSpace->fromQColor(Qt::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->fromQColor(Qt::white, MAX_SELECTED - diff, selIt.rawData()); + else + colorSpace->fromQColor(Qt::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/krita/core/kis_fill_painter.h b/krita/core/kis_fill_painter.h new file mode 100644 index 00000000..63591350 --- /dev/null +++ b/krita/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(Q_INT32 x1, Q_INT32 y1, Q_INT32 w, Q_INT32 h); + /** + * Overloaded version of the above function. + */ + void eraseRect(const QRect& rc); + + /** + * Fill a rectangle with a certain color. + */ + void fillRect(Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h, const KisColor& c); + /** + * Overloaded version of the above function. + */ + void fillRect(const QRect& rc, const KisColor& c); + + /** + * Fill a rectangle with a certain color and opacity. + */ + void fillRect(Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h, const KisColor& c, Q_UINT8 opacity); + /** + * Overloaded version of the above function. + */ + void fillRect(const QRect& rc, const KisColor& c, Q_UINT8 opacity); + + /** + * Fill a rectangle with a certain pattern. The pattern is repeated if it does not fit the + * entire rectangle. + */ + void fillRect(Q_INT32 x1, Q_INT32 y1, Q_INT32 w, Q_INT32 h, KisPattern * pattern); + /** + * Overloaded version of the above function. + */ + void fillRect(const QRect& 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 mask 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; + QRect m_rect; + bool m_sampleMerged; + bool m_careForSelection; + bool m_fuzzy; +}; + + +inline +void KisFillPainter::fillRect(Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h, const KisColor& c) +{ + fillRect(x, y, w, h, c, OPACITY_OPAQUE); +} + +inline +void KisFillPainter::fillRect(const QRect& rc, const KisColor& c) +{ + fillRect(rc.x(), rc.y(), rc.width(), rc.height(), c, OPACITY_OPAQUE); +} + +inline +void KisFillPainter::eraseRect(Q_INT32 x1, Q_INT32 y1, Q_INT32 w, Q_INT32 h) +{ + KisColorSpace * cs = KisMetaRegistry::instance()->csRegistry()->getRGB8(); + KisColor c(Qt::black, cs); + fillRect(x1, y1, w, h, c, OPACITY_TRANSPARENT); +} + +inline +void KisFillPainter::eraseRect(const QRect& rc) +{ + KisColorSpace * cs = KisMetaRegistry::instance()->csRegistry()->getRGB8(); + KisColor c(Qt::black, cs); + fillRect(rc.x(), rc.y(), rc.width(), rc.height(), c, OPACITY_TRANSPARENT); +} + +inline +void KisFillPainter::fillRect(const QRect& rc, const KisColor& c, Q_UINT8 opacity) +{ + fillRect(rc.x(), rc.y(), rc.width(), rc.height(), c, opacity); +} + +inline +void KisFillPainter::fillRect(const QRect& 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/krita/core/kis_filter.cc b/krita/core/kis_filter.cc new file mode 100644 index 00000000..05e1a92d --- /dev/null +++ b/krita/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 QString & category, const QString & entry) + : KisProgressSubject(0, id.id().latin1()) + , m_id(id) + , m_progressDisplay(0) + , m_category(category) + , m_entry(entry) +{ +} + +KisFilterConfiguration * KisFilter::configuration(QWidget*) +{ + return new KisFilterConfiguration(m_id.id(), 0); +} + +KisFilterConfiguration * KisFilter::configuration() +{ + return new KisFilterConfiguration(m_id.id(), 0); +} + +KisFilterConfigWidget * KisFilter::createConfigurationWidget(QWidget *, 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(Q_INT32 totalSteps) +{ + if (m_progressEnabled) { + + m_progressTotalSteps = totalSteps; + m_lastProgressPerCent = 0; + m_progressSteps = 0; + emit notifyProgress(0); + } +} + +void KisFilter::setProgress(Q_INT32 progress) +{ + if (m_progressEnabled) { + Q_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 QString& stage, Q_INT32 progress) +{ + if (m_progressEnabled) { + + Q_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; +} + +QRect KisFilter::enlargeRect(QRect 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/krita/core/kis_filter.h b/krita/core/kis_filter.h new file mode 100644 index 00000000..dd0f5186 --- /dev/null +++ b/krita/core/kis_filter.h @@ -0,0 +1,200 @@ +/* + * 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 QWidget; + +/** + * Basic interface of a Krita filter. + */ +class KRITACORE_EXPORT KisFilter : public KisProgressSubject, public KShared { + Q_OBJECT +public: + + /** + * Construct a Krita filter + */ + KisFilter(const KisID& id, const QString & category, const QString & entry); + virtual ~KisFilter() {} + +public: + + virtual void setProgressDisplay(KisProgressDisplayInterface * progressDisplay); + + virtual void process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration*, const QRect&) = 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(QWidget*); + + /** + * @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 QRect enlargeRect(QRect 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 QString menuCategory() const { return m_category; }; + // The i18n'ed string this filter wants to show itself in the menu + + inline QString menuEntry() const { return m_entry; }; + + /** + * Create the configuration widget for this filter. + * + * @param parent the Qt 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(QWidget * parent, 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(Q_INT32 totalSteps); + void setProgress(Q_INT32 progress); + void incProgress(); + void setProgressStage(const QString& stage, Q_INT32 progress); + void setProgressDone(); + inline Q_INT32 progress() { return m_progressSteps; } +private: + bool m_cancelRequested; + bool m_progressEnabled; + bool m_autoUpdate; + +protected: + Q_INT32 m_progressTotalSteps; + Q_INT32 m_lastProgressPerCent; + Q_INT32 m_progressSteps; + + KisID m_id; + KisProgressDisplayInterface * m_progressDisplay; + QString m_category; // The category in the filter menu this filter fits + QString m_entry; // the i18n'ed accelerated menu text + +}; + + +#endif diff --git a/krita/core/kis_filter_config_widget.cc b/krita/core/kis_filter_config_widget.cc new file mode 100644 index 00000000..e694189d --- /dev/null +++ b/krita/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(QWidget * parent, const char * name, WFlags f) + : QWidget(parent, name, f) +{ +} + +KisFilterConfigWidget::~KisFilterConfigWidget() +{ +} + +#include "kis_filter_config_widget.moc" diff --git a/krita/core/kis_filter_config_widget.h b/krita/core/kis_filter_config_widget.h new file mode 100644 index 00000000..4d93f60b --- /dev/null +++ b/krita/core/kis_filter_config_widget.h @@ -0,0 +1,49 @@ +/* + * 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 QWidget { + + Q_OBJECT + +public: + + KisFilterConfigWidget(QWidget * parent, 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/krita/core/kis_filter_configuration.cc b/krita/core/kis_filter_configuration.cc new file mode 100644 index 00000000..999edc5c --- /dev/null +++ b/krita/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 QString & s ) +{ + m_properties.clear(); + + QDomDocument doc; + doc.setContent( s ); + QDomElement e = doc.documentElement(); + QDomNode 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... + QDomElement e = n.toElement(); + QString name; + QString type; + QString 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] = QVariant(value); + } + } + n = n.nextSibling(); + } + //dump(); +} + +QString KisFilterConfiguration::toString() +{ + QDomDocument doc = QDomDocument("filterconfig"); + QDomElement root = doc.createElement( "filterconfig" ); + root.setAttribute( "name", m_name ); + root.setAttribute( "version", m_version ); + + doc.appendChild( root ); + + QMap::Iterator it; + for ( it = m_properties.begin(); it != m_properties.end(); ++it ) { + QDomElement e = doc.createElement( "property" ); + e.setAttribute( "name", it.key().latin1() ); + QVariant v = it.data(); + e.setAttribute( "type", v.typeName() ); + QString s = v.asString(); + QDomText text = doc.createCDATASection(v.asString() ); // XXX: Unittest this! + e.appendChild(text); + root.appendChild(e); + } + + return doc.toString(); +} + +const QString & KisFilterConfiguration::name() const +{ + return m_name; +} + +Q_INT32 KisFilterConfiguration::version() const +{ + return m_version; +} + +void KisFilterConfiguration::setProperty(const QString & name, const QVariant & value) +{ + if ( m_properties.find( name ) == m_properties.end() ) { + m_properties.insert( name, value ); + } + else { + m_properties[name] = value; + } +} + +bool KisFilterConfiguration::getProperty(const QString & name, QVariant & value) +{ + if ( m_properties.find( name ) == m_properties.end() ) { + return false; + } + else { + value = m_properties[name]; + return true; + } +} + +QVariant KisFilterConfiguration::getProperty(const QString & name) +{ + if ( m_properties.find( name ) == m_properties.end() ) { + return QVariant(); + } + else { + return m_properties[name]; + } +} + + +int KisFilterConfiguration::getInt(const QString & name, int def) +{ + QVariant v = getProperty(name); + if (v.isValid()) + return v.asInt(); + else + return def; + +} + +double KisFilterConfiguration::getDouble(const QString & name, double def) +{ + QVariant v = getProperty(name); + if (v.isValid()) + return v.asDouble(); + else + return def; +} + +bool KisFilterConfiguration::getBool(const QString & name, bool def) +{ + QVariant v = getProperty(name); + if (v.isValid()) + return v.asBool(); + else + return def; +} + +QString KisFilterConfiguration::getString(const QString & name, QString def) +{ + QVariant v = getProperty(name); + if (v.isValid()) + return v.asString(); + else + return def; +} + +void KisFilterConfiguration::dump() +{ + QMap::Iterator it; + for ( it = m_properties.begin(); it != m_properties.end(); ++it ) { + } + +} diff --git a/krita/core/kis_filter_configuration.h b/krita/core/kis_filter_configuration.h new file mode 100644 index 00000000..10f9a6f4 --- /dev/null +++ b/krita/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 QWidget; + +/** + * 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 QString & name, Q_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 QString &); + + /** + * Create a serialized version of this filter config + */ + virtual QString toString(); + + /** + * Get the unique, language independent name of the filter. + */ + const QString & name() const; + + /** + * Get the version of the filter that has created this config + */ + Q_INT32 version() const; + + /** + * Set the property with name to value. + */ + virtual void setProperty(const QString & name, const QVariant & value); + + /** + * Set value to the value associated with property name + * @return false if the specified property did not exist. + */ + virtual bool getProperty(const QString & name, QVariant & value); + + virtual QVariant getProperty(const QString & name); + + int getInt(const QString & name, int def = 0); + double getDouble(const QString & name, double def = 0.0); + bool getBool(const QString & name, bool def = false); + QString getString(const QString & name, QString def = QString::null); + +private: + void dump(); + +protected: + + QString m_name; + Q_INT32 m_version; + QMap m_properties; + +}; + +#endif // _KIS_FILTER_CONFIGURATION_H_ diff --git a/krita/core/kis_filter_registry.cc b/krita/core/kis_filter_registry.cc new file mode 100644 index 00000000..1b453878 --- /dev/null +++ b/krita/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(QString::fromLatin1("Krita/Filter"), + QString::fromLatin1("(Type == 'Service') and " + "([X-Krita-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, QStringList(), &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/krita/core/kis_filter_registry.h b/krita/core/kis_filter_registry.h new file mode 100644 index 00000000..89cf1341 --- /dev/null +++ b/krita/core/kis_filter_registry.h @@ -0,0 +1,52 @@ +/* + * 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 QString; +class QStringList; + +class KRITACORE_EXPORT KisFilterRegistry : public QObject, public KisGenericRegistry +{ + + Q_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/krita/core/kis_filter_strategy.cc b/krita/core/kis_filter_strategy.cc new file mode 100644 index 00000000..78dbcd41 --- /dev/null +++ b/krita/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); +} + +Q_UINT32 KisHermiteFilterStrategy::intValueAt(Q_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); +} + +Q_UINT32 KisCubicFilterStrategy::intValueAt(Q_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); +} + +Q_UINT32 KisBoxFilterStrategy::intValueAt(Q_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); +} + +Q_UINT32 KisTriangleFilterStrategy::intValueAt(Q_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/krita/core/kis_filter_strategy.h b/krita/core/kis_filter_strategy.h new file mode 100644 index 00000000..91385239 --- /dev/null +++ b/krita/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 Q_UINT32 intValueAt(Q_INT32 t) const {return Q_UINT32(255*valueAt(t/256.0));}; + double support() { return supportVal;}; + Q_UINT32 intSupport() { return intSupportVal;}; + virtual bool boxSpecial() { return false;}; + protected: + double supportVal; + Q_UINT32 intSupportVal; + KisID m_id; +}; + +class KisHermiteFilterStrategy : public KisFilterStrategy +{ + public: + KisHermiteFilterStrategy() : KisFilterStrategy(KisID("Hermite", i18n("Hermite"))) + {supportVal = 1.0; intSupportVal = 256;} + virtual ~KisHermiteFilterStrategy() {} + + virtual Q_UINT32 intValueAt(Q_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 Q_UINT32 intValueAt(Q_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 Q_UINT32 intValueAt(Q_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 Q_UINT32 intValueAt(Q_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/krita/core/kis_gradient.cc b/krita/core/kis_gradient.cc new file mode 100644 index 00000000..33714461 --- /dev/null +++ b/krita/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 QString& 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; +} + +QImage 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 QImage& 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(QValueVector::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, QColor *color, Q_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); + } +} + +QImage KisGradient::generatePreview(int width, int height) const +{ + QImage 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; + + QColor color; + Q_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, qRgb(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(QColor(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/krita/core/kis_gradient.h b/krita/core/kis_gradient.h new file mode 100644 index 00000000..3610e0e0 --- /dev/null +++ b/krita/core/kis_gradient.h @@ -0,0 +1,264 @@ +/* + * 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 QImage; + +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 QColor with KisColor +class Color { + public: + Color() { m_alpha = 0; } + Color(const QColor& color, double alpha) { m_color = color; m_alpha = alpha; } + + const QColor& color() const { return m_color; } + double alpha() const { return m_alpha; } + + private: + QColor 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 + +public: + KisGradient(const QString& file); + virtual ~KisGradient(); + + virtual bool load(); + virtual bool save(); + virtual QImage img(); + virtual QImage generatePreview(int width, int height) const; + + void colorAt(double t, QColor *color, Q_UINT8 *opacity) const; + + KisGradientSegment *segmentAt(double t) const; + +protected: + inline void pushSegment( KisGradientSegment* segment ) { m_segments.push_back(segment); }; + void setImage(const QImage& img); + + QValueVector m_segments; + +private: + bool init(); + +private: + QByteArray m_data; + QImage m_img; +}; + +#endif // KIS_GRADIENT_H + diff --git a/krita/core/kis_gradient_painter.cc b/krita/core/kis_gradient_painter.cc new file mode 100644 index 00000000..b73623aa --- /dev/null +++ b/krita/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 "qbrush.h" +#include "qcolor.h" +#include "qfontinfo.h" +#include "qfontmetrics.h" +#include "qpen.h" +#include "qregion.h" +#include "qwmatrix.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 = QMAX(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 shape, + enumGradientRepeat repeat, + double antiAliasThreshold, + bool reverseGradient, + Q_INT32 startx, + Q_INT32 starty, + Q_INT32 width, + Q_INT32 height) +{ + m_cancelRequested = false; + + if (!m_gradient) return false; + + GradientShapeStrategy *shapeStrategy = 0; + + switch (shape) { + case GradientShapeLinear: + shapeStrategy = new LinearGradientStrategy(gradientVectorStart, gradientVectorEnd); + break; + case GradientShapeBiLinear: + shapeStrategy = new BiLinearGradientStrategy(gradientVectorStart, gradientVectorEnd); + break; + case GradientShapeRadial: + shapeStrategy = new RadialGradientStrategy(gradientVectorStart, gradientVectorEnd); + break; + case GradientShapeSquare: + shapeStrategy = new SquareGradientStrategy(gradientVectorStart, gradientVectorEnd); + break; + case GradientShapeConical: + shapeStrategy = new ConicalGradientStrategy(gradientVectorStart, gradientVectorEnd); + break; + case GradientShapeConicalSymetric: + shapeStrategy = new ConicalSymetricGradientStrategy(gradientVectorStart, gradientVectorEnd); + break; + } + Q_CHECK_PTR(shapeStrategy); + + 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 + QRect r; + if( m_device->hasSelection() ) { + r = m_device->selection()->selectedExactRect(); + startx = r.x(); + starty = r.y(); + width = r.width(); + height = r.height(); + } + + Q_INT32 endx = startx + width - 1; + Q_INT32 endy = starty + height - 1; + + QImage 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 = shapeStrategy->valueAt( x, y); + t = repeatStrategy->valueAt(t); + + if (reverseGradient) { + t = 1 - t; + } + + QColor color; + Q_UINT8 opacity; + + m_gradient->colorAt(t, &color, &opacity); + + layer.setPixel(x - startx, y - starty, + qRgba(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) { + + QColor color; + emit notifyProgressStage(i18n("Anti-aliasing gradient..."), lastProgressPercent); + Q_UINT8 * layerPointer = layer.bits(); + for (int y = starty; y <= endy; y++) { + for (int x = startx; x <= endx; x++) { + + double maxDistance = 0; + + Q_UINT8 redThis = layerPointer[2]; + Q_UINT8 greenThis = layerPointer[1]; + Q_UINT8 blueThis = layerPointer[0]; + Q_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; + Q_UINT8 * pixelPos = layer.bits() + (y * width * 4) + (x * 4); + Q_UINT8 red = *(pixelPos +2); + Q_UINT8 green = *(pixelPos + 1); + Q_UINT8 blue = *pixelPos; + Q_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 = shapeStrategy->valueAt(sampleX, sampleY); + t = repeatStrategy->valueAt(t); + + if (reverseGradient) { + t = 1 - t; + } + + Q_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, qRgba(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 shapeStrategy; + + emit notifyProgressDone(); + + return !m_cancelRequested; +} diff --git a/krita/core/kis_gradient_painter.h b/krita/core/kis_gradient_painter.h new file mode 100644 index 00000000..ccfd5c3c --- /dev/null +++ b/krita/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 shape, + enumGradientRepeat repeat, + double antiAliasThreshold, + bool reverseGradient, + Q_INT32 startx, + Q_INT32 starty, + Q_INT32 width, + Q_INT32 height); + + +private: + KisGradient *m_gradient; + + +}; +#endif //KIS_GRADIENT_PAINTER_H_ diff --git a/krita/core/kis_group_layer.cc b/krita/core/kis_group_layer.cc new file mode 100644 index 00000000..2a2ed325 --- /dev/null +++ b/krita/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 QString &name, Q_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 QRect & 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 QRect & rect) +{ + // We don't have a parent, 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 (parent() == 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 = QRect(); So the non-intersecting part gets brilliantly lost otherwise. + const QRect 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->parent().data() == this) + return layer->index(); + return -1; +} + +void KisGroupLayer::setIndex(KisLayerSP layer, int index) +{ + if (layer->parent().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->parent() || m_layers.contains(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->parent().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 children, 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->parent().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); + } +} + +QRect KisGroupLayer::extent() const +{ + QRect groupExtent; + + for (vKisLayerSP_cit it = m_layers.begin(); it != m_layers.end(); ++it) + { + groupExtent |= (*it)->extent(); + } + + return groupExtent; +} + +QRect KisGroupLayer::exactBounds() const +{ + QRect groupExactBounds; + + for (vKisLayerSP_cit it = m_layers.begin(); it != m_layers.end(); ++it) + { + groupExactBounds |= (*it)->exactBounds(); + } + + return groupExactBounds; +} + +Q_INT32 KisGroupLayer::x() const +{ + return m_x; +} + +void KisGroupLayer::setX(Q_INT32 x) +{ + Q_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; +} + +Q_INT32 KisGroupLayer::y() const +{ + return m_y; +} + +void KisGroupLayer::setY(Q_INT32 y) +{ + Q_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; +} + +QImage KisGroupLayer::createThumbnail(Q_INT32 w, Q_INT32 h) +{ + return m_projection->createThumbnail(w, h); +} + +void KisGroupLayer::updateProjection(const QRect & 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 children, 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 = (parent() != 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 mask/selection into account, so we need + // to make a difference between a paintlayer with a mask, 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/krita/core/kis_group_layer.h b/krita/core/kis_group_layer.h new file mode 100644 index 00000000..7b1a764a --- /dev/null +++ b/krita/core/kis_group_layer.h @@ -0,0 +1,140 @@ +/* + * 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 + +public: + KisGroupLayer(KisImage *img, const QString &name, Q_UINT8 opacity); + KisGroupLayer(const KisGroupLayer& rhs); + virtual ~KisGroupLayer(); + + virtual KisLayerSP clone() const; +public: + + /** + * Set the entire layer extent dirty; this percolates up to parent 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 parent layers all the way to the root + * layer. + */ + virtual void setDirty(const QRect & rect, bool propagate = true); + + virtual void activate() {}; + + virtual void deactivate() {}; + + virtual Q_INT32 x() const; + virtual void setX(Q_INT32); + + virtual Q_INT32 y() const; + virtual void setY(Q_INT32); + + // Sets this layer and all its descendants' owner image to the given image. + virtual void setImage(KisImage *image); + + virtual QRect extent() const; + virtual QRect exactBounds() const; + + virtual bool accept(KisLayerVisitor &v) + { +// kdDebug(41001) << "GROUP\t\t" << name() +// << " dirty: " << dirty() +// << ", " << m_layers.count() << " children " +// << ", 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 QRect & 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 QImage createThumbnail(Q_INT32 w, Q_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(QRect rc); + +private: + + void updateProjection(const QRect & 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 + + Q_INT32 m_x; + Q_INT32 m_y; +}; + +#endif // KIS_GROUP_LAYER_H_ + diff --git a/krita/core/kis_histogram.cc b/krita/core/kis_histogram.cc new file mode 100644 index 00000000..97fdeac4 --- /dev/null +++ b/krita/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() +{ + Q_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(); + + QTime 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); +} + +QValueVector KisHistogram::calculateForRange(double from, double to) { + QValueVector 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; + Q_UINT32 high = 0, low = (Q_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; + } + + Q_INT32 totbins = m_producer->numberOfBins(); + Q_UINT32 current; + + // convert the double range into actual bins: + double factor = static_cast(totbins) / m_producer->viewWidth(); + + Q_INT32 fromBin = static_cast((from - m_producer->viewFrom()) * factor); + Q_INT32 toBin = fromBin + static_cast((to - from) * factor); + + // Min, max, count, low, high + for (Q_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 " + << QString().setNum(i) + << ": " + << QString().setNum(m_values[i]) + << "\n"; + }*/ + kdDebug(DBG_AREA_MATH) << "\n"; + + kdDebug(DBG_AREA_MATH) << "Max: " << QString().setNum(c.getMax()) << "\n"; + kdDebug(DBG_AREA_MATH) << "Min: " << QString().setNum(c.getMin()) << "\n"; + kdDebug(DBG_AREA_MATH) << "High: " << QString().setNum(c.getHighest()) << "\n"; + kdDebug(DBG_AREA_MATH) << "Low: " << QString().setNum(c.getLowest()) << "\n"; + kdDebug(DBG_AREA_MATH) << "Mean: " << m_producer->positionToString(c.getMean()) << "\n"; + kdDebug(DBG_AREA_MATH) << "Total: " << QString().setNum(c.getTotal()) << "\n"; +// kdDebug(DBG_AREA_MATH) << "Median: " << QString().setNum(m_median) << "\n"; +// kdDebug(DBG_AREA_MATH) << "Stddev: " << QString().setNum(m_stddev) << "\n"; +// kdDebug(DBG_AREA_MATH) << "percentile: " << QString().setNum(m_percentile) << "\n"; + + kdDebug(DBG_AREA_MATH) << "\n"; +} diff --git a/krita/core/kis_histogram.h b/krita/core/kis_histogram.h new file mode 100644 index 00000000..3365bde1 --- /dev/null +++ b/krita/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; + + Q_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 Q_UINT32 getHighest() { return m_high; } + /// This function return the lowest value of the histogram + inline Q_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 Q_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; } + //Q_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 Q_UINT32 getValue(Q_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(Q_INT32 channel) { m_channel = channel; } + inline KisHistogramProducerSP producer() { return m_producer; } + inline Q_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(); + QValueVector calculateForRange(double from, double to); + Calculations calculateSingleRange(int channel, double from, double to); + + KisPaintDeviceSP m_device; + KisHistogramProducerSP m_producer; + + enumHistogramType m_type; + + Q_INT32 m_channel; + double m_selFrom, m_selTo; + bool m_selection; + + KisPaintDeviceSP m_dev; + + QValueVector m_completeCalculations, m_selectionCalculations; +}; + + +#endif // KIS_HISTOGRAM_WIDGET_ diff --git a/krita/core/kis_image.cc b/krita/core/kis_image.cc new file mode 100644 index 00000000..2c56b606 --- /dev/null +++ b/krita/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; + Q_UINT32 lockCount; + bool sizeChangedWhileLocked; + bool selectionChangedWhileLocked; + KisSubstrateSP substrate; + KisPerspectiveGrid* perspectiveGrid; +}; + + +namespace { + + class KisResizeImageCmd : public KNamedCommand { + typedef KNamedCommand super; + + public: + KisResizeImageCmd(KisUndoAdapter *adapter, + KisImageSP img, + Q_INT32 width, + Q_INT32 height, + Q_INT32 oldWidth, + Q_INT32 oldHeight) : super(i18n("Resize Image")) + { + m_adapter = adapter; + m_img = img; + m_before = QSize(oldWidth, oldHeight); + m_after = QSize(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; + QSize m_before; + QSize m_after; + }; + + // ------------------------------------------------------- + + class KisChangeLayersCmd : public KNamedCommand { + typedef KNamedCommand super; + + public: + KisChangeLayersCmd(KisUndoAdapter *adapter, KisImageSP img, + KisGroupLayerSP oldRootLayer, KisGroupLayerSP newRootLayer, const QString& 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 QString& name, KisImageSP image); + virtual ~KisImageCommand() {} + + virtual void execute() = 0; + virtual void unexecute() = 0; + + protected: + void setUndo(bool undo); + + KisImageSP m_image; + }; + + KisImageCommand::KisImageCommand(const QString& 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 QString& name, KisImageSP image, KisLayerSP layer, KisGroupLayerSP parent, KisLayerSP aboveThis) : super(name, image) + { + m_layer = layer; + m_oldParent = layer->parent(); + m_oldAboveThis = layer->nextSibling(); + m_newParent = parent; + 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->parent(); + 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->parent(); + 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 QString& name, + Q_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() + { + QString name = m_layer->name(); + Q_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; + QString m_name; + Q_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, Q_INT32 width, Q_INT32 height, KisColorSpace * colorSpace, const QString& name) + : QObject(0, name.latin1()), KShared() +{ + init(adapter, width, height, colorSpace, name); + setName(name); + m_dcop = 0L; +} + +KisImage::KisImage(const KisImage& rhs) : QObject(), 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 = QString::null; + 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, SIGNAL(sigDirty(QRect)), this, SIGNAL(sigImageUpdated(QRect))); + + 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) { + QString 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; +} + +QString KisImage::name() const +{ + return m_name; +} + +void KisImage::setName(const QString& name) +{ + if (!name.isEmpty()) + m_name = name; +} + +QString KisImage::description() const +{ + return m_description; +} + +void KisImage::setDescription(const QString& 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; +} + + +QString 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, Q_INT32 width, Q_INT32 height, KisColorSpace * colorSpace, const QString& 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(Qt::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, SIGNAL(sigDirty(QRect)), this, SIGNAL(sigImageUpdated(QRect))); + + 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, SIGNAL(sigDirty(QRect)), this, SIGNAL(sigImageUpdated(QRect))); + 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, SIGNAL(sigDirty(QRect)), this, SIGNAL(sigImageUpdated(QRect))); + } + } +} + +void KisImage::emitSizeChanged() +{ + if (!locked()) { + emit sigSizeChanged(m_width, m_height); + } else { + m_private->sizeChangedWhileLocked = true; + } +} + +void KisImage::notifyLayerUpdated(KisLayerSP layer, QRect rc) +{ + emit sigLayerUpdated(layer, rc); +} + +void KisImage::resize(Q_INT32 w, Q_INT32 h, Q_INT32 x, Q_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(QRect(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 QRect& 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? + Q_INT32 w, h; + w = (Q_INT32)(( width() * sx) + 0.5); + h = (Q_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(); + + Q_INT32 w = width(); + Q_INT32 h = height(); + Q_INT32 tx = Q_INT32((w*cos(radians) - h*sin(radians) - w) / 2 + 0.5); + Q_INT32 ty = Q_INT32((h*cos(radians) + w*sin(radians) - h) / 2 + 0.5); + w = (Q_INT32)(width()*QABS(cos(radians)) + height()*QABS(sin(radians)) + 0.5); + h = (Q_INT32)(height()*QABS(cos(radians)) + width()*QABS(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 + Q_INT32 w=width(); + Q_INT32 h=height(); + + + if(angleX != 0 || angleY != 0){ + double deltaY=height()*QABS(tan(angleX*pi/180)*tan(angleY*pi/180)); + w = (Q_INT32) ( width() + QABS(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 = (Q_INT32) ( height() + QABS(w*tan(angleY*pi/180)) ); + else if (angleX > 0 && angleY > 0) + h = (Q_INT32) ( height() + QABS(w*tan(angleY*pi/180))- 2 * deltaY + 2 ); + else if (angleX < 0 && angleY < 0) + h = (Q_INT32) ( height() + QABS(w*tan(angleY*pi/180))- 2 * deltaY + 2 ); + else + h = (Q_INT32) ( height() + QABS(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, Q_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; +} + +Q_INT32 KisImage::width() const +{ + return m_width; +} + +Q_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 QString& name, Q_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->parent().data(), m_activeLayer->nextSibling()); + } + else { + addLayer(layer, m_rootLayer, 0); + } + activate(layer); + + return layer; +} + +void KisImage::setLayerProperties(KisLayerSP layer, Q_UINT8 opacity, const KisCompositeOp& compositeOp, const QString& name) +{ + if (layer && (layer->opacity() != opacity || layer->compositeOp() != compositeOp || layer->name() != name)) { + if (undo()) { + QString oldname = layer->name(); + Q_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(QRect(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 QString& name) const +{ + return rootLayer()->findLayer(name); +} + +KisLayerSP KisImage::findLayer(int id) const +{ + return rootLayer()->findLayer(id); +} + + +bool KisImage::addLayer(KisLayerSP layer, KisGroupLayerSP parent) +{ + return addLayer(layer, parent, parent->firstChild()); +} + +bool KisImage::addLayer(KisLayerSP layer, KisGroupLayerSP parent, KisLayerSP aboveThis) +{ + if (!parent) + return false; + + const bool success = parent->addLayer(layer, aboveThis); + if (success) + { + KisPaintLayerSP player = dynamic_cast(layer.data()); + if (player != 0) { + + // XXX: This should also be done whenever a layer grows! + QValueVector 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, SIGNAL(sigMaskInfoChanged()), this, 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 parent = layer->parent()) { + // 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) { + QRect 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, SIGNAL(sigMaskInfoChanged()), + this, SIGNAL(sigMaskInfoChanged())); + } + KisLayerSP l = layer->prevSibling(); + QRect 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 = parent->removeLayer(layer); + if (success) { + layer->setImage(0); + if (!layer->temporary() && undo()) { + m_adapter->addCommand(new LayerRmCmd(m_adapter, this, layer, parent, wasAbove)); + } + if (!layer->temporary()) { + emit sigLayerRemoved(layer, parent, wasAbove); + if (wasActive) { + if (wasBelow) + activate(wasBelow); + else if (wasAbove) + activate(wasAbove); + else if (parent != rootLayer()) + activate(parent.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->parent().data(), layer->prevSibling()); +} + +bool KisImage::lowerLayer(KisLayerSP layer) +{ + if (!layer) + return false; + if (KisLayerSP next = layer->nextSibling()) + return moveLayer(layer, layer->parent().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 parent, KisLayerSP aboveThis) +{ + if (!parent) + return false; + + KisGroupLayerSP wasParent = layer->parent(); + KisLayerSP wasAbove = layer->nextSibling(); + + if (wasParent.data() == parent.data() && wasAbove.data() == aboveThis.data()) + return false; + + lock(); + + if (!wasParent->removeLayer(layer)) { + unlock(); + return false; + } + + const bool success = parent->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; +} + +Q_INT32 KisImage::nlayers() const +{ + return rootLayer()->numLayers() - 1; +} + +Q_INT32 KisImage::nHiddenLayers() const +{ + return rootLayer()->numLayers(KisLayer::Hidden); +} + +void KisImage::flatten() +{ + KisGroupLayerSP oldRootLayer = m_rootLayer; + disconnect(oldRootLayer, SIGNAL(sigDirty(QRect)), this, SIGNAL(sigImageUpdated(QRect))); + + KisPaintLayer *dst = new KisPaintLayer(this, nextLayerName(), OPACITY_OPAQUE, colorSpace()); + Q_CHECK_PTR(dst); + + QRect 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, SIGNAL(sigDirty(QRect)), this, SIGNAL(sigImageUpdated(QRect))); + + 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); + + QRect 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->parent(), layer); + removeLayer(layer); + + undoAdapter()->endMacro(); +} + + +void KisImage::setModified() +{ + emit sigImageModified(); +} + +void KisImage::renderToPainter(Q_INT32 x1, + Q_INT32 y1, + Q_INT32 x2, + Q_INT32 y2, + QPainter &painter, + KisProfile * monitorProfile, + PaintFlags paintFlags, + float exposure) +{ + + QImage img = convertToQImage(x1, y1, x2, y2, monitorProfile, exposure); + + Q_INT32 w = x2 - x1 + 1; + Q_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); +} + +QImage KisImage::convertToQImage(Q_INT32 x1, + Q_INT32 y1, + Q_INT32 x2, + Q_INT32 y2, + KisProfile * profile, + float exposure) +{ + Q_INT32 w = x2 - x1 + 1; + Q_INT32 h = y2 - y1 + 1; + + KisPaintDeviceSP dev = m_rootLayer->projection(QRect(x1, y1, w, h)); + QImage img = dev->convertToQImage(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 QImage(); +} + +QImage KisImage::convertToQImage(const QRect& r, const QSize& scaledImageSize, KisProfile *profile, PaintFlags paintFlags, float exposure) +{ + + if (r.isEmpty() || scaledImageSize.isEmpty()) { + return QImage(); + } + + Q_INT32 imageWidth = width(); + Q_INT32 imageHeight = height(); + Q_UINT32 pixelSize = colorSpace()->pixelSize(); + + double xScale = static_cast(imageWidth) / scaledImageSize.width(); + double yScale = static_cast(imageHeight) / scaledImageSize.height(); + + QRect 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); + QTime t; + t.start(); + + Q_UINT8 *scaledImageData = new Q_UINT8[r.width() * r.height() * pixelSize]; + + Q_UINT8 *imageRow = new Q_UINT8[srcRect.width() * pixelSize]; + const Q_INT32 imageRowX = srcRect.x(); + + for (Q_INT32 y = 0; y < r.height(); ++y) { + + Q_INT32 dstY = r.y() + y; + Q_INT32 dstX = r.x(); + Q_INT32 srcY = (dstY * imageHeight) / scaledImageSize.height(); + + mergedImage->readBytes(imageRow, imageRowX, srcY, srcRect.width(), 1); + + Q_UINT8 *dstPixel = scaledImageData + (y * r.width() * pixelSize); + Q_UINT32 columnsRemaining = r.width(); + + while (columnsRemaining > 0) { + + Q_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; + + QImage image = colorSpace()->convertToQImage(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, QSize(imageWidth, imageHeight)); + image.setAlphaBuffer(false); + } + + if (paintFlags & PAINT_SELECTION) { + if (m_activeLayer != 0) { + m_activeLayer->paintSelection(image, r, scaledImageSize, QSize(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(QRect(0, 0, m_width, m_height)); +} + +KisColor KisImage::mergedPixel(Q_INT32 x, Q_INT32 y) +{ + return m_rootLayer->projection(QRect(x, y, 1, 1))->colorAt(x, y); +} + +void KisImage::notifyLayersChanged() +{ + emit sigLayersChanged(rootLayer()); +} + +void KisImage::notifyPropertyChanged(KisLayerSP layer) +{ + emit sigLayerPropertiesChanged(layer); +} + +void KisImage::notifyImageLoaded() +{ +} + +QRect KisImage::bounds() const +{ + return QRect(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 QRect& r) +{ + QRect 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, SIGNAL(sigDirty(QRect)), this, SIGNAL(sigImageUpdated(QRect))); + + m_rootLayer = rootLayer; + + if (!locked()) { + connect(m_rootLayer, SIGNAL(sigDirty(QRect)), this, SIGNAL(sigImageUpdated(QRect))); + } + 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(QString type) +{ + vKisAnnotationSP_it it = m_annotations.begin(); + while (it != m_annotations.end()) { + if ((*it)->type() == type) { + return *it; + } + ++it; + } + return 0; +} + +void KisImage::removeAnnotation(QString 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/krita/core/kis_image.h b/krita/core/kis_image.h new file mode 100644 index 00000000..fccb2fd3 --- /dev/null +++ b/krita/core/kis_image.h @@ -0,0 +1,460 @@ +/* + * 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 QObject, public KShared { + Q_OBJECT + +public: + KisImage(KisUndoAdapter * adapter, Q_INT32 width, Q_INT32 height, KisColorSpace * colorSpace, const QString& 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(Q_INT32 x1, + Q_INT32 y1, + Q_INT32 x2, + Q_INT32 y2, + QPainter &painter, + KisProfile *profile, + PaintFlags paintFlags, + float exposure = 0.0f); + /** + * Render the projection onto a QImage. In contrast with the above method, the + * selection is not rendered. + */ + virtual QImage convertToQImage(Q_INT32 x1, + Q_INT32 y1, + Q_INT32 x2, + Q_INT32 y2, + KisProfile * profile, + float exposure = 0.0f); + + virtual QImage convertToQImage(const QRect& r, const QSize& 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 Krita 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); + + QString name() const; + void setName(const QString& name); + + QString description() const; + void setDescription(const QString& description); + + QString nextLayerName() const; + void rollBackLayerName(); + + KisPerspectiveGrid* perspectiveGrid(); + void createPerspectiveGrid(QPoint topLeft, QPoint topRight, QPoint bottomRight, QPoint 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(Q_INT32 w, Q_INT32 h, Q_INT32 x = 0, Q_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 QRect& 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, Q_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); + + Q_INT32 width() const; + Q_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(Q_INT32 x, Q_INT32 y); + + /// Creates a new paint layer with the specified properties, adds it to the image, and returns it. + KisLayerSP newLayer(const QString& name, Q_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, Q_UINT8 opacity, const KisCompositeOp& compositeOp, const QString& 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 QString& name) const; + KisLayerSP findLayer(int id) const; + + /// Move layer to specified position + bool moveLayer(KisLayerSP layer, KisGroupLayerSP parent, 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 parent the parent layer + */ + bool addLayer(KisLayerSP layer, KisGroupLayerSP parent); + + /** + * Add already existing layer to image. + * + * @param layer the layer to be added + * @param parent the parent layer + * @param aboveThis in the list with child layers of the specified + * parent, 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 parent, 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); + + Q_INT32 nlayers() const; + Q_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); + + QRect bounds() const; + + /// use if the layers have changed _completely_ (eg. when flattening) + void notifyLayersChanged(); + + void notifyPropertyChanged(KisLayerSP layer); + + void notifyImageLoaded(); + + void notifyLayerUpdated(KisLayerSP layer, QRect 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(QString type); + + /** delete the annotation, if the image contains it */ + void removeAnnotation(QString 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 QRect& 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 parent(), 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 parent the parent 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 parent layer, or its parent changes. + + @param previousParent the parent 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(QRect 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, QRect rc); + + /** + * Emitted whenever the image has been modified, so that it doesn't match with the version saved on disk. + */ + void sigImageModified(); + + void sigSizeChanged(Q_INT32 w, Q_INT32 h); + void sigProfileChanged(KisProfile * profile); + void sigColorSpaceChanged(KisColorSpace* cs); + + + /// Emitted when any layer's mask info got updated (or when the current layer changes) + void sigMaskInfoChanged(); +public slots: + void slotSelectionChanged(); + void slotSelectionChanged(const QRect& r); + + +private: + KisImage& operator=(const KisImage& rhs); + void init(KisUndoAdapter * adapter, Q_INT32 width, Q_INT32 height, KisColorSpace * colorSpace, const QString& name); + void emitSizeChanged(); + +private: + + KURL m_uri; + QString m_name; + QString m_description; + + Q_INT32 m_width; + Q_INT32 m_height; + + double m_xres; + double m_yres; + + KoUnit::Unit m_unit; + + KisColorSpace * m_colorSpace; + + bool m_dirty; + QRect 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/krita/core/kis_image_iface.cc b/krita/core/kis_image_iface.cc new file mode 100644 index 00000000..5a74c480 --- /dev/null +++ b/krita/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 QString& 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/krita/core/kis_image_iface.h b/krita/core/kis_image_iface.h new file mode 100644 index 00000000..77baa516 --- /dev/null +++ b/krita/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 QString& 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/krita/core/kis_imagepipe_brush.cc b/krita/core/kis_imagepipe_brush.cc new file mode 100644 index 00000000..ad745014 --- /dev/null +++ b/krita/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 QString& source) +{ + needsMovement = false; + QRegExp basicSplitter(" ", true); + QRegExp parasiteSplitter(":", true); + QStringList parasites = QStringList::split(basicSplitter, source); + for (uint i = 0; i < parasites.count(); i++) { + QStringList splitted = QStringList::split(parasiteSplitter, *parasites.at(i)); + if (splitted.count() != 2) { + kdWarning(41001) << "Wrong count for this parasite key/value:" << *parasites.at(i) << endl; + continue; + } + QString 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) { + QString 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(QIODevice* dev) const { + // write out something like + // ncells: dim: rank0: sel0: <...> + + QTextStream 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 QString& filename) : super(filename) +{ + m_brushType = INVALID; + m_numOfBrushes = 0; + m_currentBrush = 0; +} + +KisImagePipeBrush::KisImagePipeBrush(const QString& name, int w, int h, + QValueVector< QValueVector > devices, + QValueVector 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() +{ + QFile 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 + QValueVector line1; + + Q_UINT32 i = 0; + + while (m_data[i] != '\n' && i < m_data.size()) { + line1.append(m_data[i]); + i++; + } + setName(i18n(QString::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. + QValueVector line2; + while (m_data[i] != '\n' && i < m_data.size()) { + line2.append(m_data[i]); + i++; + } + + QString paramline = QString::fromUtf8((&line2[0]), line2.size()); + Q_UINT32 m_numOfBrushes = paramline.left(paramline.find(' ')).toUInt(); + m_parasite = paramline.mid(paramline.find(' ') + 1); + i++; // Skip past the second newline + + Q_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() +{ + QFile file(filename()); + file.open(IO_WriteOnly | IO_Truncate); + bool ok = saveToDevice(&file); + file.close(); + return ok; +} + +bool KisImagePipeBrush::saveToDevice(QIODevice* dev) const +{ + QCString utf8Name = name().utf8(); // Names in v2 brushes are in UTF-8 + char const* name = utf8Name.data(); + int len = qstrlen(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; +} + +QImage KisImagePipeBrush::img() +{ + if (m_brushes.isEmpty()) { + return 0; + } + else { + return m_brushes.at(0)->img(); + } +} + +KisAlphaMaskSP KisImagePipeBrush::mask(const KisPaintInformation& info, double subPixelX, double subPixelY) const +{ + if (m_brushes.isEmpty()) return 0; + selectNextBrush(info); + return m_brushes.at(m_currentBrush)->mask(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 QString& 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... + QValueVector< QValueVector > devices; + QValueVector modes; + + devices.push_back(QValueVector()); + 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->convertFromQImage(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/krita/core/kis_imagepipe_brush.h b/krita/core/kis_imagepipe_brush.h new file mode 100644 index 00000000..8a183848 --- /dev/null +++ b/krita/core/kis_imagepipe_brush.h @@ -0,0 +1,168 @@ +/* + * 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 QCString; +class QImage; +class QPoint; +class QSize; + +/** + * 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 QString& source); + /** + * Saves a GIMP-compatible representation of this parasite to the device. Also writes the + * number of brushes (== ncells) (no trailing '\n') */ + bool saveToDevice(QIODevice* 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; + //Q_INT32 step; + Q_INT32 ncells; + Q_INT32 dim; + // Apparantly only used for editing a pipe brush, which we won't at the moment + // Q_INT32 cols, rows; + // Q_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; + Q_INT32 rank[MaxDim]; + SelectionMode selection[MaxDim]; + /// The total count of brushes in each dimension (helper) + Q_INT32 brushesCount[MaxDim]; + /// The current index in each dimension, so that the selection modes know where to start + Q_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 + +public: + KisImagePipeBrush(const QString& 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 QString& name, int w, int h, + QValueVector< QValueVector > devices, + QValueVector modes); + virtual ~KisImagePipeBrush(); + + virtual bool load(); + virtual bool save(); + /// Will call KisBrush's saveToDevice as well + virtual bool saveToDevice(QIODevice* dev) const; + + /** + @return the next image in the pipe. + */ + virtual QImage img(); + + /** + @return the next mask in the pipe. + */ + virtual KisAlphaMaskSP mask(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 QString& parasite); + void selectNextBrush(const KisPaintInformation& info) const; + + QString m_name; + QString m_parasiteString; // Contains instructions on how to use the brush + mutable KisPipeBrushParasite m_parasite; + Q_UINT32 m_numOfBrushes; + mutable Q_UINT32 m_currentBrush; + + QByteArray m_data; + mutable QPtrList m_brushes; + + enumBrushType m_brushType; + +}; + +#endif // KIS_IMAGEPIPE_BRUSH_ diff --git a/krita/core/kis_iterator.cc b/krita/core/kis_iterator.cc new file mode 100644 index 00000000..f43f3d5b --- /dev/null +++ b/krita/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, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_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() +{ +} + +Q_UINT8 * KisRectIterator::rawData() const { return m_iter->rawData();} + +const Q_UINT8 * KisRectIterator::oldRawData() const { return m_iter->oldRawData();} + +Q_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(); } + +Q_INT32 KisRectIterator::x() const { return m_iter->x(); } +Q_INT32 KisRectIterator::y() const { return m_iter->y(); } + +//--------------------------------------------------------------------------------------- + +KisHLineIterator::KisHLineIterator ( KisDataManager *dm, Q_INT32 x, Q_INT32 y, Q_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() +{ +} + +Q_UINT8 *KisHLineIterator::rawData() const +{ + return m_iter->rawData(); +} + +const Q_UINT8 *KisHLineIterator::oldRawData() const { return m_iter->oldRawData();} + +KisHLineIterator & KisHLineIterator::operator++() { m_iter->operator++(); return *this; } + +Q_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(); } + +Q_INT32 KisHLineIterator::x() const { return m_iter->x(); } + +Q_INT32 KisHLineIterator::y() const { return m_iter->y(); } + +void KisHLineIterator::nextRow() { m_iter->nextRow(); } + +//--------------------------------------------------------------------------------------- + +KisVLineIterator::KisVLineIterator ( KisDataManager *dm, Q_INT32 x, Q_INT32 y, Q_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() +{ +} + +Q_UINT8 *KisVLineIterator::rawData() const { return m_iter->rawData();} + +const Q_UINT8 * KisVLineIterator::oldRawData() const { return m_iter->oldRawData();} + +KisVLineIterator & KisVLineIterator::operator++() { m_iter->operator++(); return *this; } + +bool KisVLineIterator::isDone() const { return m_iter->isDone(); } + +Q_INT32 KisVLineIterator::x() const { return m_iter->x(); } + +Q_INT32 KisVLineIterator::y() const { return m_iter->y(); } + +void KisVLineIterator::nextCol() { return m_iter->nextCol(); } diff --git a/krita/core/kis_iterator.h b/krita/core/kis_iterator.h new file mode 100644 index 00000000..67206272 --- /dev/null +++ b/krita/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, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_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 + Q_UINT8 * rawData() const; + + /// Returns a pointer to the pixel data as it was at the moment of the last memento creation. + const Q_UINT8 * oldRawData() const; + + /// Returns the number of consequtive pixels that we point at + /// This is useful for optimizing + Q_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 + Q_INT32 x() const; + + // current y position + Q_INT32 y() const; + +private: + + KisTiledRectIteratorSP m_iter; +}; + +class KisHLineIterator +{ + +public: + + KisHLineIterator ( KisDataManager *dm, Q_INT32 x, Q_INT32 y, Q_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 + Q_UINT8 *rawData() const; + + /// Returns a pointer to the pixel data as it was at the moment of the last memento creation. + const Q_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 + Q_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 + Q_INT32 x() const; + + /// current y position + Q_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, Q_INT32 x, Q_INT32 y, Q_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 + Q_UINT8 *rawData() const; + + /// Returns a pointer to the pixel data as it was at the moment of the last memento creation. + const Q_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 + Q_INT32 x() const; + + /// current y position + Q_INT32 y() const; + + /// increment to the next column and rewind to the begining + void nextCol(); + +private: + + KisTiledVLineIteratorSP m_iter; + +}; + +#endif diff --git a/krita/core/kis_iteratorpixeltrait.h b/krita/core/kis_iteratorpixeltrait.h new file mode 100644 index 00000000..5aadad56 --- /dev/null +++ b/krita/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 Q_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 Q_UINT8 selectedness() const + { + if (m_selectionIterator) + return *(m_selectionIterator->rawData()); + else { + return MAX_SELECTED; + } + }; + + /** + * Returns the selectionmask 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 Q_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/krita/core/kis_iterators_pixel.cc b/krita/core/kis_iterators_pixel.cc new file mode 100644 index 00000000..062fde73 --- /dev/null +++ b/krita/core/kis_iterators_pixel.cc @@ -0,0 +1,59 @@ +/* + * This file is part of the Krita 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, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 offsetx, Q_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, Q_INT32 x, Q_INT32 y, Q_INT32 h, Q_INT32 offsetx, Q_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, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h, Q_INT32 offsetx, Q_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/krita/core/kis_iterators_pixel.h b/krita/core/kis_iterators_pixel.h new file mode 100644 index 00000000..ad7d7f1f --- /dev/null +++ b/krita/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, + Q_INT32 x , Q_INT32 y , Q_INT32 w, Q_INT32 offsetx, Q_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; }; + + Q_INT32 x() const { return KisHLineIterator::x() + m_offsetx; } + + Q_INT32 y() const { return KisHLineIterator::y() + m_offsety; } + + Q_INT32 nConseqHPixels() const { + if (m_selectionIterator) { + Q_INT32 parent = KisHLineIteratorPixel::nConseqHPixels(); + Q_INT32 selection = m_selectionIterator->nConseqHPixels(); + if (parent < selection) + return parent; + return selection; + } + return KisHLineIteratorPixel::nConseqHPixels(); + } +protected: + + Q_INT32 m_offsetx, m_offsety; +}; + +class KisVLineIteratorPixel : public KisVLineIterator, public KisIteratorPixelTrait +{ +public: + KisVLineIteratorPixel( KisPaintDevice *ndevice, KisDataManager *dm, KisDataManager *sel_dm, + Q_INT32 xpos , Q_INT32 ypos , Q_INT32 height, Q_INT32 offsetx, Q_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(); + } + + Q_INT32 x() const { return KisVLineIterator::x() + m_offsetx; } + + Q_INT32 y() const { return KisVLineIterator::y() + m_offsety; } + +protected: + + Q_INT32 m_offsetx, m_offsety; +}; + +class KisRectIteratorPixel : public KisRectIterator, public KisIteratorPixelTrait +{ +public: + KisRectIteratorPixel( KisPaintDevice *ndevice, KisDataManager *dm, KisDataManager *sel_dm, + Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h, Q_INT32 offsetx, Q_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;} + + Q_INT32 x() const { return KisRectIterator::x() + m_offsetx; } + + Q_INT32 y() const { return KisRectIterator::y() + m_offsety; } + + Q_INT32 nConseqPixels() const { + if (m_selectionIterator) { + Q_INT32 parent = KisRectIterator::nConseqPixels(); + Q_INT32 selection = m_selectionIterator->nConseqPixels(); + if (parent < selection) + return parent; + return selection; + } + return KisRectIterator::nConseqPixels(); + } + +protected: + + Q_INT32 m_offsetx, m_offsety; +}; + +#endif diff --git a/krita/core/kis_layer.cc b/krita/core/kis_layer.cc new file mode 100644 index 00000000..b19a4dcf --- /dev/null +++ b/krita/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 QString& name, KisLayerSP layer); + virtual ~KisLayerCommand() {} + + virtual void execute() = 0; + virtual void unexecute() = 0; + + protected: + void setUndo(bool undo); + + KisLayerSP m_layer; + }; + + KisLayerCommand::KisLayerCommand(const QString& 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, Q_UINT8 oldOpacity, Q_UINT8 newOpacity); + + virtual void execute(); + virtual void unexecute(); + + private: + Q_UINT8 m_oldOpacity; + Q_UINT8 m_newOpacity; + }; + + KisLayerOpacityCommand::KisLayerOpacityCommand(KisLayerSP layer, Q_UINT8 oldOpacity, Q_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 QPoint& oldpos, const QPoint& newpos); + virtual ~KisLayerOffsetCommand(); + + virtual void execute(); + virtual void unexecute(); + + private: + void moveTo(const QPoint& pos); + + private: + KisLayerSP m_layer; + QRect m_updateRect; + QPoint m_oldPos; + QPoint m_newPos; + }; + + KisLayerOffsetCommand::KisLayerOffsetCommand(KisLayerSP layer, const QPoint& oldpos, const QPoint& newpos) : + super(i18n("Move Layer")) + { + m_layer = layer; + m_oldPos = oldpos; + m_newPos = newpos; + + QRect currentBounds = m_layer->exactBounds(); + QRect 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 QPoint& 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 QString &name, Q_UINT8 opacity) : + QObject(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) : + QObject(), + 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 QRect & 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.contains(m_dirtyRect)) m_dirtyRect = QRect(); + m_dirtyRect = QRect(); + } + +} + +bool KisLayer::dirty() +{ + return m_dirtyRect.isValid(); +} + + +bool KisLayer::dirty(const QRect & rc) +{ + if (!m_dirtyRect.isValid() || !rc.isValid()) return false; + + return rc.intersects(m_dirtyRect); +} + +QRect KisLayer::dirtyRect() const +{ + return m_dirtyRect; +} + +void KisLayer::setDirty(bool propagate) +{ + QRect rc = extent(); + + if (rc.isValid()) m_dirtyRect = rc; + + // If we're dirty, our parent is dirty, if we've got a parent + 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 QRect & rc, bool propagate) +{ + // If we're dirty, our parent is dirty, if we've got a parent + + 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::parent() const +{ + return m_parent; +} + +KisLayerSP KisLayer::prevSibling() const +{ + if (!parent()) + return 0; + return parent()->at(index() - 1); +} + +KisLayerSP KisLayer::nextSibling() const +{ + if (!parent()) + return 0; + return parent()->at(index() + 1); +} + +int KisLayer::index() const +{ + return m_index; +} + +void KisLayer::setIndex(int i) +{ + if (!parent()) + return; + parent()->setIndex(this, i); +} + +KisLayerSP KisLayer::findLayer(const QString& 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; +} + +Q_UINT8 KisLayer::opacity() const +{ + return m_opacity; +} + +void KisLayer::setOpacity(Q_UINT8 val) +{ + if (m_opacity != val) + { + m_opacity = val; + setDirty(); + notifyPropertyChanged(); + } +} + +KNamedCommand *KisLayer::setOpacityCommand(Q_UINT8 newOpacity) +{ + return new KisLayerOpacityCommand(this, opacity(), newOpacity); +} + +KNamedCommand *KisLayer::setOpacityCommand(Q_UINT8 prevOpacity, Q_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); +} + +QString KisLayer::name() const +{ + return m_name; +} + +void KisLayer::setName(const QString& 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(QPoint oldPosition, QPoint newPosition) +{ + return new KisLayerOffsetCommand(this, oldPosition, newPosition); +} + +KisUndoAdapter *KisLayer::undoAdapter() const +{ + if (m_image) { + return m_image->undoAdapter(); + } + return 0; +} + +void KisLayer::paintMaskInactiveLayers(QImage &, Q_INT32, Q_INT32, Q_INT32, Q_INT32) +{ +} + +void KisLayer::paintSelection(QImage &, Q_INT32, Q_INT32, Q_INT32, Q_INT32) +{ +} + +void KisLayer::paintSelection(QImage &, const QRect&, const QSize&, const QSize&) +{ +} + +QImage KisLayer::createThumbnail(Q_INT32, Q_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(Q_UINT8 o) { + m_compositeOpacity = o; +} + +KisPaintDeviceSP KisLayerSupportsIndirectPainting::temporaryTarget() { + return m_temporaryTarget; +} + +KisCompositeOp KisLayerSupportsIndirectPainting::temporaryCompositeOp() const { + return m_compositeOp; +} + +Q_UINT8 KisLayerSupportsIndirectPainting::temporaryOpacity() const { + return m_compositeOpacity; +} + +#include "kis_layer.moc" diff --git a/krita/core/kis_layer.h b/krita/core/kis_layer.h new file mode 100644 index 00000000..5da5181d --- /dev/null +++ b/krita/core/kis_layer.h @@ -0,0 +1,256 @@ +/* + * 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 QPainter; +class KisUndoAdapter; +class KisGroupLayer; + +/** + * Abstract class that represents the concept of a Layer in Krita. 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 QObject, public KShared +{ + Q_OBJECT + +public: + KisLayer(KisImage *img, const QString &name, Q_UINT8 opacity); + KisLayer(const KisLayer& rhs); + virtual ~KisLayer(); + + + /** + * Set the specified rect to clean + */ + virtual void setClean(const QRect & 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 QRect & rc); + + + virtual QRect dirtyRect() const; + + + /** + * Set the entire layer extent dirty; this percolates up to parent 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 parent layers all the way to the root + * layer. + */ + virtual void setDirty(const QRect & 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 parent'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 parent's list of child layers. + virtual void setIndex(int index); + + /** + * Returns the parent layer of a layer. This is 0 only for a root layer; otherwise + * this will be an actual GroupLayer */ + virtual KisGroupLayerSP parent() const; + + /** + * Returns the previous sibling of this layer in the parent's list. This is the layer + * *above* this layer. 0 is returned if there is no parent, or if this child has no more + * previous siblings (== firstChild()) + */ + virtual KisLayerSP prevSibling() const; + + /** + * Returns the next sibling of this layer in the parent's list. This is the layer *below* + * this layer. 0 is returned if there is no parent, or if this child has no more next + * siblings (== lastChild()) + */ + virtual KisLayerSP nextSibling() const; + + /** + * Returns the sibling above this layer in its parent's list. 0 is returned if there is no parent, + * 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 parent's list. 0 is returned if there is no parent, + * 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 QString& 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 Q_INT32 x() const = 0; + virtual void setX(Q_INT32) = 0; + + virtual Q_INT32 y() const = 0; + virtual void setY(Q_INT32) = 0; + + virtual KNamedCommand *moveCommand(QPoint oldPosition, QPoint newPosition); + + /// Returns an approximation of where the bounds on actual data are in this layer + virtual QRect extent() const = 0; + /// Returns the exact bounds of where the actual data resides in this layer + virtual QRect exactBounds() const = 0; + + virtual const bool visible() const; + virtual void setVisible(bool v); + KNamedCommand *setVisibleCommand(bool visiblel); + + Q_UINT8 opacity() const; + void setOpacity(Q_UINT8 val); + KNamedCommand *setOpacityCommand(Q_UINT8 val); + KNamedCommand *setOpacityCommand(Q_UINT8 prevOpacity, Q_UINT8 newOpacity); + + bool locked() const; + void setLocked(bool l); + KNamedCommand *setLockedCommand(bool locked); + + void notifyPropertyChanged(); + + bool temporary() const; + void setTemporary(bool t); + + virtual QString name() const; + virtual void setName(const QString& 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 mask where the selection on this layer resides + virtual void paintSelection(QImage &img, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h); + virtual void paintSelection(QImage &img, const QRect& scaledImageRect, const QSize& scaledImageSize, const QSize& 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(QImage &img, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h); + + /// Returns a thumbnail in requested size. The QImage may have transparent parts. + /// May also return 0 + virtual QImage createThumbnail(Q_INT32 w, Q_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; + Q_UINT8 m_opacity; + bool m_locked; + bool m_visible; + bool m_temporary; + + // XXX: keep a list of dirty rects instead of always aggegrating them + QRect m_dirtyRect; + QString 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; + Q_UINT8 m_compositeOpacity; +public: + // Indirect painting + void setTemporaryTarget(KisPaintDeviceSP t); + void setTemporaryCompositeOp(const KisCompositeOp& c); + void setTemporaryOpacity(Q_UINT8 o); + KisPaintDeviceSP temporaryTarget(); + KisCompositeOp temporaryCompositeOp() const; + Q_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/krita/core/kis_layer_visitor.h b/krita/core/kis_layer_visitor.h new file mode 100644 index 00000000..4326bc54 --- /dev/null +++ b/krita/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/krita/core/kis_math_toolbox.cpp b/krita/core/kis_math_toolbox.cpp new file mode 100644 index 00000000..d0f49e71 --- /dev/null +++ b/krita/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(Q_UINT8* data, int channelpos ) +{ + return (float)( *((T*)(data + channelpos)) ); +} + +typedef double (*PtrToDouble)(Q_UINT8*, int); + +template +void fromDouble(Q_UINT8* data, int channelpos, double v ) +{ + *((T*)(data + channelpos)) = (T)v; +} + +typedef void (*PtrFromDouble)(Q_UINT8*, int, double); + + +void KisMathToolbox::transformToFR(KisPaintDeviceSP src, KisFloatRepresentation* fr, const QRect& rect) +{ + Q_INT32 depth = src->colorSpace()->nColorChannels(); + QMemArray f(depth); + QValueVector cis = src->colorSpace()->channels(); + for(Q_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() ) + { + Q_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 QRect& rect) +{ + Q_INT32 depth = dst->colorSpace()->nColorChannels(); + QMemArray f(depth); + QValueVector cis = dst->colorSpace()->channels(); + for(Q_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() ) + { + Q_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/krita/core/kis_math_toolbox.h b/krita/core/kis_math_toolbox.h new file mode 100644 index 00000000..0ddc545f --- /dev/null +++ b/krita/core/kis_math_toolbox.h @@ -0,0 +1,123 @@ +/* + * 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 QObject { + Q_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 (Q_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 QRect&) throw(std::bad_alloc ); + inline uint fastWaveletTotalSteps(const QRect&); + /** + * 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 QRect&, 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 QRect&, 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 QRect&); + /** + * 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 QRect&); + private: + KisID m_id; +}; + +class KisMathToolboxFactoryRegistry : public KisGenericRegistry { + public: + KisMathToolboxFactoryRegistry(); + ~KisMathToolboxFactoryRegistry(); +}; + + +inline KisMathToolbox::KisWavelet* KisMathToolbox::initWavelet(KisPaintDeviceSP src, const QRect& rect) throw(std::bad_alloc ) +{ + int size; + int maxrectsize = (rect.height() < rect.width()) ? rect.width() : rect.height(); + for(size = 2; size < maxrectsize; size *= 2) ; + Q_INT32 depth = src->colorSpace()->nColorChannels(); + return new KisWavelet(size, depth); +} + +inline uint KisMathToolbox::fastWaveletTotalSteps(const QRect& 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/krita/core/kis_merge_visitor.h b/krita/core/kis_merge_visitor.h new file mode 100644 index 00000000..73331591 --- /dev/null +++ b/krita/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 QRect& 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, + Q_INT32 sx, Q_INT32 sy, Q_INT32 dx, Q_INT32 dy, + Q_INT32 w, Q_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; + + Q_INT32 sx, sy, dx, dy, w, h; + + QRect 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 mask, 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 mask 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 mask might not be extended + // enough. Check if that is the case + KisPaintDeviceSP mask = layer->getMask(); + QRect mextent = mask->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 = mask->createRectIterator(sx, sy, w, h, true); + while (!it.isDone()) + ++it; + } + if (tempTarget) { + KisPaintDeviceSP temp = new KisPaintDevice(source->colorSpace()); + mask = paintIndirect(mask, temp, layer, sx, sy, dx, dy, w, h); + } + + gc.bitBlt(dx, dy, COMPOSITE_OVER, mask, OPACITY_OPAQUE, sx, sy, w, h); + } else { + KisSelectionSP mask = layer->getMaskAsSelection(); + // The indirect painting happens on the mask + if (tempTarget && layer->editMask()) { + KisPaintDeviceSP maskSrc = layer->getMask(); + KisPaintDeviceSP temp = new KisPaintDevice(maskSrc->colorSpace()); + temp = paintIndirect(maskSrc, temp, layer, sx, sy, dx, dy, w, h); + // Blegh + KisRectIteratorPixel srcIt = temp->createRectIterator(sx, sy, w, h, false); + KisRectIteratorPixel dstIt = mask->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 mask, and paint indirect, but not on the mask + KisPaintDeviceSP temp = new KisPaintDevice(source->colorSpace()); + source = paintIndirect(source, temp, layer, sx, sy, dx, dy, w, h); + } + + gc.bltSelection(dx, dy, + layer->compositeOp(), + source, + mask, + 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; + + Q_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); + QRect 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; + + Q_INT32 sx, sy, dx, dy, w, h; + + QRect 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); + QRect 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; + QRect m_rc; +}; + +#endif // KIS_MERGE_H_ + diff --git a/krita/core/kis_meta_registry.cc b/krita/core/kis_meta_registry.cc new file mode 100644 index 00000000..70f21f76 --- /dev/null +++ b/krita/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") + "krita/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") + "krita/profiles/"); + KGlobal::instance()->dirs()->addResourceDir("kis_profiles", "/usr/share/color/icc"); + KGlobal::instance()->dirs()->addResourceDir("kis_profiles", QDir::homeDirPath() + QString("/.icc/")); + KGlobal::instance()->dirs()->addResourceDir("kis_profiles", QDir::homeDirPath() + QString("/.color/icc/")); + + QStringList 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/krita/core/kis_meta_registry.h b/krita/core/kis_meta_registry.h new file mode 100644 index 00000000..42aeee3d --- /dev/null +++ b/krita/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/krita/core/kis_nameserver.cc b/krita/core/kis_nameserver.cc new file mode 100644 index 00000000..bdc59ca2 --- /dev/null +++ b/krita/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 QString& prefix, Q_INT32 seed) +{ + m_prefix = prefix; + m_generator = seed; +} + +KisNameServer::~KisNameServer() +{ +} + +QString KisNameServer::name() +{ + return m_prefix.arg(m_generator++); +} + +Q_INT32 KisNameServer::currentSeed() const +{ + return m_generator; +} + +Q_INT32 KisNameServer::number() +{ + return m_generator++; +} + +void KisNameServer::rollback() +{ + m_generator--; +} + diff --git a/krita/core/kis_nameserver.h b/krita/core/kis_nameserver.h new file mode 100644 index 00000000..1e4c560d --- /dev/null +++ b/krita/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 QString& prefix, Q_INT32 seed = 1); + ~KisNameServer(); + + QString name(); + Q_INT32 number(); + Q_INT32 currentSeed() const; + void rollback(); + +private: + Q_INT32 m_generator; + QString m_prefix; +}; + +#endif // KIS_NAMESERVER_H_ + diff --git a/krita/core/kis_paint_device.cc b/krita/core/kis_paint_device.cc new file mode 100644 index 00000000..4bf15c1d --- /dev/null +++ b/krita/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 QString& name, KisPaintDeviceSP paintDevice); + virtual ~KisPaintDeviceCommand() {} + + virtual void execute() = 0; + virtual void unexecute() = 0; + + protected: + void setUndo(bool undo); + + KisPaintDeviceSP m_paintDevice; + }; + + KisPaintDeviceCommand::KisPaintDeviceCommand(const QString& 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 QPoint& oldpos, const QPoint& newpos); + virtual ~MoveCommand(); + + virtual void execute(); + virtual void unexecute(); + + private: + void moveTo(const QPoint& pos); + void undoOff(); + void undoOn(); + + private: + KisPaintDeviceSP m_device; + QPoint m_oldPos; + QPoint m_newPos; + }; + + MoveCommand::MoveCommand(KisPaintDeviceSP device, const QPoint& oldpos, const QPoint& 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 QPoint& 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) : + QObject(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(); + + Q_UINT8* defPixel = new Q_UINT8 [ m_pixelSize ]; + colorSpace->fromQColor(Qt::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 *parent, KisColorSpace * colorSpace, const char * name) : + QObject(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 = parent; + + if (colorSpace == 0 && parent != 0 && parent->image() != 0) { + m_colorSpace = parent->image()->colorSpace(); + } + else { + m_colorSpace = colorSpace; + } + + Q_ASSERT( m_colorSpace ); + + m_pixelSize = m_colorSpace->pixelSize(); + m_nChannels = m_colorSpace->nChannels(); + + Q_UINT8* defPixel = new Q_UINT8[ m_pixelSize ]; + m_colorSpace->fromQColor(Qt::black, OPACITY_TRANSPARENT, defPixel); + + m_datamanager = new KisDataManager(m_pixelSize, defPixel); + delete [] defPixel; + Q_CHECK_PTR(m_datamanager); + m_extentIsValid = true; + + if ( QString ( name ) == QString( "Layer 1" ) ) { + m_longRunningFilters = m_colorSpace->createBackgroundFilters(); + + if (!m_longRunningFilters.isEmpty()) { + m_longRunningFilterTimer = new QTimer(this); + connect(m_longRunningFilterTimer, SIGNAL(timeout()), this, SLOT(runBackgroundFilters())); + m_longRunningFilterTimer->start(2000); + } + } +} + + +KisPaintDevice::KisPaintDevice(const KisPaintDevice& rhs) : QObject(), 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; + QValueList::iterator it; + QValueList::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::parentLayer() const +{ + return m_parentLayer; +} + +void KisPaintDevice::setParentLayer(KisLayer *parentLayer) +{ + m_parentLayer = parentLayer; +} + +void KisPaintDevice::setDirty(const QRect & 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(Q_INT32 x, Q_INT32 y) +{ + QRect 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 QPoint& pt) +{ + move(pt.x(), pt.y()); +} + +KNamedCommand * KisPaintDevice::moveCommand(Q_INT32 x, Q_INT32 y) +{ + KNamedCommand * cmd = new MoveCommand(this, QPoint(m_x, m_y), QPoint(x, y)); + Q_CHECK_PTR(cmd); + cmd->execute(); + return cmd; +} + +void KisPaintDevice::extent(Q_INT32 &x, Q_INT32 &y, Q_INT32 &w, Q_INT32 &h) const +{ + m_datamanager->extent(x, y, w, h); + x += m_x; + y += m_y; +} + +QRect KisPaintDevice::extent() const +{ + Q_INT32 x, y, w, h; + extent(x, y, w, h); + return QRect(x, y, w, h); +} + +bool KisPaintDevice::extentIsValid() const +{ + return m_extentIsValid; +} + +void KisPaintDevice::setExtentIsValid(bool isValid) +{ + m_extentIsValid = isValid; +} + +void KisPaintDevice::exactBounds(Q_INT32 &x, Q_INT32 &y, Q_INT32 &w, Q_INT32 &h) const +{ + QRect r = exactBounds(); + x = r.x(); + y = r.y(); + w = r.width(); + h = r.height(); +} + +QRect KisPaintDevice::exactBoundsOldMethod() const +{ + Q_INT32 x, y, w, h, boundX, boundY, boundW, boundH; + extent(x, y, w, h); + + extent(boundX, boundY, boundW, boundH); + + const Q_UINT8* defaultPixel = m_datamanager->defaultPixel(); + + bool found = false; + + for (Q_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 (Q_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 (Q_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 (Q_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 QRect(boundX, boundY, boundW, boundH); +} + +QRect KisPaintDevice::exactBoundsImprovedOldMethod() const +{ + // Solution n°2 + Q_INT32 x, y, w, h, boundX2, boundY2, boundW2, boundH2; + extent(x, y, w, h); + extent(boundX2, boundY2, boundW2, boundH2); + + const Q_UINT8* defaultPixel = m_datamanager->defaultPixel(); + bool found = false; + { + KisHLineIterator it = const_cast(this)->createHLineIterator(x, y, w, false); + for (Q_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 (Q_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 (Q_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 (Q_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 QRect(boundX2, boundY2, boundW2, boundH2); +} + + +QRect KisPaintDevice::exactBounds() const +{ + QRect r2 = exactBoundsImprovedOldMethod(); + return r2; +} + +void KisPaintDevice::crop(Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h) +{ + m_datamanager->setExtent(x - m_x, y - m_y, w, h); +} + + +void KisPaintDevice::crop(QRect r) +{ + r.moveBy(-m_x, -m_y); m_datamanager->setExtent(r); +} + +void KisPaintDevice::clear() +{ + m_datamanager->clear(); +} + +void KisPaintDevice::fill(Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h, const Q_UINT8 *fillPixel) +{ + m_datamanager->clear(x, y, w, h, fillPixel); +} + +void KisPaintDevice::mirrorX() +{ + QRect r; + if (hasSelection()) { + r = selection()->selectedRect(); + } + else { + r = exactBounds(); + } + + for (Q_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 */ + QRect r; + if (hasSelection()) { + r = selection()->selectedRect(); + } + else { + r = exactBounds(); + } + + + Q_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, Q_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()); + + Q_INT32 x, y, w, h; + extent(x, y, w, h); + + for (Q_INT32 row = y; row < y + h; ++row) { + + Q_INT32 column = x; + Q_INT32 columnsRemaining = w; + + while (columnsRemaining > 0) { + + Q_INT32 numContiguousDstColumns = dst.numContiguousColumns(column, row, row); + Q_INT32 numContiguousSrcColumns = numContiguousColumns(column, row, row); + + Q_INT32 columns = QMIN(numContiguousDstColumns, numContiguousSrcColumns); + columns = QMIN(columns, columnsRemaining); + + //const Q_UINT8 *srcData = pixel(column, row); + //Q_UINT8 *dstData = dst.writablePixel(column, row); + KisHLineIteratorPixel srcIt = createHLineIterator(column, row, columns, false); + KisHLineIteratorPixel dstIt = dst.createHLineIterator(column, row, columns, true); + + const Q_UINT8 *srcData = srcIt.rawData(); + Q_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::convertFromQImage(const QImage& image, const QString &srcProfileName, + Q_INT32 offsetX, Q_INT32 offsetY) +{ + QImage img = image; + + // Krita is little-endian inside. + if (img.bitOrder() == QImage::LittleEndian) { + img = img.convertBitOrder(QImage::BigEndian); + } + kdDebug() << k_funcinfo << img.bitOrder()<< endl; + // Krita 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 + Q_UINT8 * dstData = new Q_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()); +// } +} + +QImage KisPaintDevice::convertToQImage(KisProfile * dstProfile, float exposure) +{ + Q_INT32 x1; + Q_INT32 y1; + Q_INT32 w; + Q_INT32 h; + + x1 = - getX(); + y1 = - getY(); + + if (image()) { + w = image()->width(); + h = image()->height(); + } + else { + extent(x1, y1, w, h); + } + + return convertToQImage(dstProfile, x1, y1, w, h, exposure); +} + +// XXX: is this faster than building the QImage ourselves? It makes +QImage KisPaintDevice::convertToQImage(KisProfile * dstProfile, Q_INT32 x1, Q_INT32 y1, Q_INT32 w, Q_INT32 h, float exposure) +{ + if (w < 0) + return QImage(); + + if (h < 0) + return QImage(); + + Q_UINT8 * data = new Q_UINT8 [w * h * m_pixelSize]; + Q_CHECK_PTR(data); + + // XXX: Is this really faster than converting line by line and building the QImage directly? + // This copies potentially a lot of data. + readBytes(data, x1, y1, w, h); + QImage image = colorSpace()->convertToQImage(data, w, h, dstProfile, INTENT_PERCEPTUAL, exposure); + delete[] data; + + return image; +} + +KisPaintDeviceSP KisPaintDevice::createThumbnailDevice(Q_INT32 w, Q_INT32 h) +{ + KisPaintDeviceSP thumbnail = new KisPaintDevice(colorSpace(), "thumbnail"); + + thumbnail->clear(); + + int srcw, srch; + if( image() ) + { + srcw = image()->width(); + srch = image()->height(); + } + else + { + const QRect e = exactBounds(); + srcw = e.width(); + srch = e.height(); + } + + if (w > srcw) + { + w = srcw; + h = Q_INT32(double(srcw) / w * h); + } + if (h > srch) + { + h = srch; + w = Q_INT32(double(srch) / h * w); + } + + if (srcw > srch) + h = Q_INT32(double(srch) / srcw * w); + else if (srch > srcw) + w = Q_INT32(double(srcw) / srch * h); + + for (Q_INT32 y=0; y < h; ++y) { + Q_INT32 iY = (y * srch ) / h; + for (Q_INT32 x=0; x < w; ++x) { + Q_INT32 iX = (x * srcw ) / w; + thumbnail->setPixel(x, y, colorAt(iX, iY)); + } + } + + return thumbnail; + +} + + +QImage KisPaintDevice::createThumbnail(Q_INT32 w, Q_INT32 h) +{ + int srcw, srch; + if( image() ) + { + srcw = image()->width(); + srch = image()->height(); + } + else + { + const QRect e = extent(); + srcw = e.width(); + srch = e.height(); + } + + if (w > srcw) + { + w = srcw; + h = Q_INT32(double(srcw) / w * h); + } + if (h > srch) + { + h = srch; + w = Q_INT32(double(srch) / h * w); + } + + if (srcw > srch) + h = Q_INT32(double(srch) / srcw * w); + else if (srch > srcw) + w = Q_INT32(double(srcw) / srch * h); + + QColor c; + Q_UINT8 opacity; + QImage img(w,h,32); + + for (Q_INT32 y=0; y < h; ++y) { + Q_INT32 iY = (y * srch ) / h; + for (Q_INT32 x=0; x < w; ++x) { + Q_INT32 iX = (x * srcw ) / w; + pixel(iX, iY, &c, &opacity); + const QRgb rgb = c.rgb(); + img.setPixel(x, y, qRgba(qRed(rgb), qGreen(rgb), qBlue(rgb), opacity)); + } + } + + return img; +} + +KisRectIteratorPixel KisPaintDevice::createRectIterator(Q_INT32 left, Q_INT32 top, Q_INT32 w, Q_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(Q_INT32 x, Q_INT32 y, Q_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(Q_INT32 x, Q_INT32 y, Q_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(Q_INT32 x, Q_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 QRect& 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()); + QRect 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(); + + QRect 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; + + QRect r = m_selection->selectedExactRect(); + + if (r.isValid()) { + + 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()) { + // 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 mask) +{ + QRect r = mask->selectedRect(); + crop(r); + + for (Q_INT32 y = r.top(); y <= r.bottom(); ++y) { + + KisHLineIterator pixelIt = createHLineIterator(r.x(), y, r.width(), true); + KisHLineIterator maskIt = mask->createHLineIterator(r.x(), y, r.width(), false); + + while (!pixelIt.isDone()) { + // XXX: Optimize by using stretches + + m_colorSpace->applyAlphaU8Mask( pixelIt.rawData(), maskIt.rawData(), 1); + + ++pixelIt; + ++maskIt; + } + } +} + +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(Q_INT32 x, Q_INT32 y, QColor *c, Q_UINT8 *opacity) +{ + KisHLineIteratorPixel iter = createHLineIterator(x, y, 1, false); + + Q_UINT8 *pix = iter.rawData(); + + if (!pix) return false; + + colorSpace()->toQColor(pix, c, opacity); + + return true; +} + + +bool KisPaintDevice::pixel(Q_INT32 x, Q_INT32 y, KisColor * kc) +{ + KisHLineIteratorPixel iter = createHLineIterator(x, y, 1, false); + + Q_UINT8 *pix = iter.rawData(); + + if (!pix) return false; + + kc->setColor(pix, m_colorSpace); + + return true; +} + +KisColor KisPaintDevice::colorAt(Q_INT32 x, Q_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(Q_INT32 x, Q_INT32 y, const QColor& c, Q_UINT8 opacity) +{ + KisHLineIteratorPixel iter = createHLineIterator(x, y, 1, true); + + colorSpace()->fromQColor(c, opacity, iter.rawData()); + + return true; +} + +bool KisPaintDevice::setPixel(Q_INT32 x, Q_INT32 y, const KisColor& kc) +{ + Q_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; +} + + +Q_INT32 KisPaintDevice::numContiguousColumns(Q_INT32 x, Q_INT32 minY, Q_INT32 maxY) +{ + return m_datamanager->numContiguousColumns(x - m_x, minY - m_y, maxY - m_y); +} + +Q_INT32 KisPaintDevice::numContiguousRows(Q_INT32 y, Q_INT32 minX, Q_INT32 maxX) +{ + return m_datamanager->numContiguousRows(y - m_y, minX - m_x, maxX - m_x); +} + +Q_INT32 KisPaintDevice::rowStride(Q_INT32 x, Q_INT32 y) +{ + return m_datamanager->rowStride(x - m_x, y - m_y); +} + +const Q_UINT8* KisPaintDevice::pixel(Q_INT32 x, Q_INT32 y) +{ + return m_datamanager->pixel(x - m_x, y - m_y); +} + +Q_UINT8* KisPaintDevice::writablePixel(Q_INT32 x, Q_INT32 y) +{ + return m_datamanager->writablePixel(x - m_x, y - m_y); +} + +void KisPaintDevice::setX(Q_INT32 x) +{ + m_x = x; + if(m_selection && m_selection != this) + m_selection->setX(x); +} + +void KisPaintDevice::setY(Q_INT32 y) +{ + m_y = y; + if(m_selection && m_selection != this) + m_selection->setY(y); +} + + +void KisPaintDevice::readBytes(Q_UINT8 * data, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h) +{ + m_datamanager->readBytes(data, x - m_x, y - m_y, w, h); +} + +void KisPaintDevice::writeBytes(const Q_UINT8 * data, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_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); + + QRect rc = extent(); + if (!m_longRunningFilters.isEmpty()) { + QValueList::iterator it; + QValueList::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/krita/core/kis_paint_device.h b/krita/core/kis_paint_device.h new file mode 100644 index 00000000..3b1dcfe7 --- /dev/null +++ b/krita/core/kis_paint_device.h @@ -0,0 +1,596 @@ +/* + * 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 QImage; +class QSize; +class QPoint; +class QWMatrix; +class QTimer; + +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 QObject + , public KShared +{ + + Q_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 + * parentLayer will be notified of changes to this paint device. + * + * @param parentLayer the layer that contains this paint device. + * @param colorSpace the colorspace of this paint device + * @param name for debugging purposes + */ + KisPaintDevice(KisLayer *parentLayer, 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(Q_INT32 x, Q_INT32 y); + + /** + * Convenience method for the above + */ + virtual void move(const QPoint& pt); + + /** + * Move the paint device to the specified location and make it possible to + * undo the move. + */ + virtual KNamedCommand * moveCommand(Q_INT32 x, Q_INT32 y); + + /** + * Returns true of x,y is within the extent of this paint device + */ + bool contains(Q_INT32 x, Q_INT32 y) const; + + /** + * Convenience method for the above + */ + bool contains(const QPoint& 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(Q_INT32 &x, Q_INT32 &y, Q_INT32 &w, Q_INT32 &h) const; + virtual QRect 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(Q_INT32 &x, Q_INT32 &y, Q_INT32 &w, Q_INT32 &h) const; + virtual QRect exactBounds() const; + virtual QRect exactBoundsOldMethod() const; + virtual QRect exactBoundsImprovedOldMethod() const; + + /** + * Cut the paint device down to the specified rect + */ + void crop(Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h); + + /// Convience method for the above + void crop(QRect 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(Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h, const Q_UINT8 *fillPixel); + + /** + * Read the bytes representing the rectangle described by x, y, w, h into + * data. If data is not big enough, Krita 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(Q_UINT8 * data, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h); + + /** + * Copy the bytes in data into the rect specified by x, y, w, h. If the + * data is too small or uninitialized, Krita 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 Q_UINT8 * data, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h); + + /** + * Get the number of contiguous columns starting at x, valid for all values + * of y between minY and maxY. + */ + Q_INT32 numContiguousColumns(Q_INT32 x, Q_INT32 minY, Q_INT32 maxY); + + /** + * Get the number of contiguous rows starting at y, valid for all values + * of x between minX and maxX. + */ + Q_INT32 numContiguousRows(Q_INT32 y, Q_INT32 minX, Q_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). + */ + Q_INT32 rowStride(Q_INT32 x, Q_INT32 y); + + /** + * Get a read-only pointer to pixel (x, y). + */ + KDE_DEPRECATED const Q_UINT8* pixel(Q_INT32 x, Q_INT32 y); + + /** + * Get a read-write pointer to pixel (x, y). + */ + KDE_DEPRECATED Q_UINT8* writablePixel(Q_INT32 x, Q_INT32 y); + + /** + * Converts the paint device to a different colorspace + */ + virtual void convertTo(KisColorSpace * dstColorSpace, Q_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 convertFromQImage(const QImage& img, const QString &srcProfileName, Q_INT32 offsetX = 0, Q_INT32 offsetY = 0); + + /** + * Create an RGBA QImage 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 QImage convertToQImage(KisProfile * dstProfile, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h, float exposure = 0.0f); + + /** + * Create an RGBA QImage from a rectangle in the paint device. The rectangle is defined by the parent 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 QImage convertToQImage(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(Q_INT32 w, Q_INT32 h); + + /** + * Creates a thumbnail of the paint device, retaining the aspect ratio. + * The width and height of the returned QImage won't exceed \p maxw and \p maxw, but they may be smaller. + * The colors are not corrected for display! + */ + virtual QImage createThumbnail(Q_INT32 maxw, Q_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(Q_INT32 x, Q_INT32 y, QColor *c, Q_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(Q_INT32 x, Q_INT32 y, KisColor * kc); + + /** + * Return the KisColor of the pixel at x,y. + */ + KisColor colorAt(Q_INT32 x, Q_INT32 y); + + /** + * Set the specified pixel to the specified color. Note that this + * bypasses KisPainter. the PaintDevice is here used as an equivalent + * to QImage, not QPixmap. 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(Q_INT32 x, Q_INT32 y, const QColor& c, Q_UINT8 opacity); + + bool setPixel(Q_INT32 x, Q_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 + */ + Q_INT32 getX() const; + + /** + * The Y offset of the paint device + */ + Q_INT32 getY() const; + + /** + * Return the X offset of the paint device + */ + void setX(Q_INT32 x); + + /** + * Return the Y offset of the paint device + */ + void setY(Q_INT32 y); + + + /** + * Return the number of bytes a pixel takes. + */ + virtual Q_INT32 pixelSize() const; + + /** + * Return the number of channels a pixel takes + */ + virtual Q_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 parentLayer()->image(). + */ + KisImage *image() const; + + /** + * Returns the KisLayer that contains this paint device, or 0 if this is not + * part of a layer. + */ + KisLayer *parentLayer() const; + + /** + * Set the KisLayer that contains this paint device, or 0 if this is not + * part of a layer. + */ + void setParentLayer(KisLayer *parentLayer); + + /** + * Add the specified rect top the parent layer (if present) + */ + virtual void setDirty(const QRect & rc); + + /** + * Set the parent 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(Q_INT32 left, Q_INT32 top, Q_INT32 w, Q_INT32 h, bool writable); + + /** + * This function return an iterator which points to the first pixel of a horizontal line + */ + KisHLineIteratorPixel createHLineIterator(Q_INT32 x, Q_INT32 y, Q_INT32 w, bool writable); + + /** + * This function return an iterator which points to the first pixel of a vertical line + */ + KisVLineIteratorPixel createVLineIterator(Q_INT32 x, Q_INT32 y, Q_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(Q_INT32 x, Q_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 mask to the image data, i.e. multiply each pixel's opacity by its + * selectedness in the mask. + */ + void applySelectionMask(KisSelectionSP mask); + + /** + * 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 QRect& 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(Q_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; + + Q_INT32 m_x; + Q_INT32 m_y; + KisColorSpace * m_colorSpace; + // Cached for quick access + Q_INT32 m_pixelSize; + Q_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; + + QValueList m_longRunningFilters; + QTimer * m_longRunningFilterTimer; + + bool m_lock; +}; + +inline Q_INT32 KisPaintDevice::pixelSize() const +{ + Q_ASSERT(m_pixelSize > 0); + return m_pixelSize; +} + +inline Q_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 Q_INT32 KisPaintDevice::getX() const +{ + return m_x; +} + +inline Q_INT32 KisPaintDevice::getY() const +{ + return m_y; +} + +#endif // KIS_PAINT_DEVICE_IMPL_H_ + diff --git a/krita/core/kis_paint_device_action.h b/krita/core/kis_paint_device_action.h new file mode 100644 index 00000000..4dbbc365 --- /dev/null +++ b/krita/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 QString; + +/** + * 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, Q_INT32 w = 0, Q_INT32 h = 0) const = 0; + /// The name of the action, to be displayed in the GUI + virtual QString name() const = 0; + /// A description of the action, to be displayed in the GUI + virtual QString description() const = 0; +}; + +#endif // KIS_PAINTDEV_ACTION_H_ diff --git a/krita/core/kis_paint_device_iface.cc b/krita/core/kis_paint_device_iface.cc new file mode 100644 index 00000000..ff4c7034 --- /dev/null +++ b/krita/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 * parent ) + : DCOPObject("paintdevice") +{ + m_parent = parent; +} + +Q_INT32 KisPaintDeviceIface::pixelSize() const +{ + return m_parent->pixelSize(); +} + +Q_INT32 KisPaintDeviceIface::nChannels() const +{ + return m_parent->nChannels(); +} + +QByteArray KisPaintDeviceIface::readBytes(Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h) +{ + QByteArray b (w * h * m_parent->pixelSize()); + + m_parent->readBytes((Q_UINT8*)b.data(), x, y, w, h); + return b; +} + +void KisPaintDeviceIface::writeBytes(QByteArray bytes, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h) +{ + m_parent->writeBytes((Q_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/krita/core/kis_paint_device_iface.h b/krita/core/kis_paint_device_iface.h new file mode 100644 index 00000000..d712f410 --- /dev/null +++ b/krita/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 * parent ); +k_dcop: + + /** + * Return the number of bytes a pixel takes. + */ + Q_INT32 pixelSize() const; + + /** + * Return the number of channels a pixel takes + */ + Q_INT32 nChannels() const; + + /** + * Read the bytes representing the rectangle described by x, y, w, h into + * data. If data is not big enough, Krita 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. + */ + QByteArray readBytes(Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h); + + /** + * Copy the bytes in data into the rect specified by x, y, w, h. If there + * data is too small or uninitialized, Krita 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(QByteArray bytes, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_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/krita/core/kis_paint_layer.cc b/krita/core/kis_paint_layer.cc new file mode 100644 index 00000000..2567c75c --- /dev/null +++ b/krita/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 QString& name, Q_UINT8 opacity, KisPaintDeviceSP dev) + : super(img, name, opacity) +{ + Q_ASSERT(img); + Q_ASSERT(dev); + m_paintdev = dev; + m_mask = 0; + m_maskAsSelection = 0; + m_paintdev->setParentLayer(this); + m_renderMask = false; + m_editMask = true; +} + + +KisPaintLayer::KisPaintLayer(KisImage *img, const QString& name, Q_UINT8 opacity) + : super(img, name, opacity) +{ + Q_ASSERT(img); + m_paintdev = new KisPaintDevice(this, img->colorSpace(), name.latin1()); + m_mask = 0; + m_maskAsSelection = 0; + m_renderMask = false; + m_editMask = true; +} + +KisPaintLayer::KisPaintLayer(KisImage *img, const QString& name, Q_UINT8 opacity, KisColorSpace * colorSpace) + : super(img, name, opacity) +{ + Q_ASSERT(img); + Q_ASSERT(colorSpace); + m_paintdev = new KisPaintDevice(this, colorSpace, name.latin1()); + m_mask = 0; + m_maskAsSelection = 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_mask = new KisPaintDevice(*rhs.m_mask.data()); + m_mask->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_mask != 0) { + m_mask->setParentLayer(0); + } +} + +void KisPaintLayer::paintSelection(QImage &img, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h) +{ + if (m_paintdev && m_paintdev->hasSelection()) { + m_paintdev->selection()->paintSelection(img, x, y, w, h); + } else if (m_mask && m_editMask && m_mask->hasSelection()) { + m_mask->selection()->paintSelection(img, x, y, w, h); + } +} + +void KisPaintLayer::paintSelection(QImage &img, const QRect& scaledImageRect, const QSize& scaledImageSize, const QSize& imageSize) +{ + if (m_paintdev && m_paintdev->hasSelection()) { + m_paintdev->selection()->paintSelection(img, scaledImageRect, scaledImageSize, imageSize); + } else if (m_mask && m_editMask && m_mask->hasSelection()) { + m_mask->selection()->paintSelection(img, scaledImageRect, scaledImageSize, imageSize); + } +} + +void KisPaintLayer::paintMaskInactiveLayers(QImage &img, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h) +{ + uchar *j = img.bits(); + + KisColorSpace *cs = m_paintdev->colorSpace(); + + for (Q_INT32 y2 = y; y2 < h + y; ++y2) { + KisHLineIteratorPixel it = m_paintdev->createHLineIterator(x, y2, w, false); + while ( ! it.isDone()) { + Q_UINT8 s = cs->getAlpha(it.rawData()); + if(s==0) + { + Q_UINT8 g = (*(j + 0) + *(j + 1 ) + *(j + 2 )) / 9; + + *(j+0) = 128+g ; + *(j+1) = 165+g; + *(j+2) = 128+g; + } + j+=4; + ++it; + } + } +} + +QImage KisPaintLayer::createThumbnail(Q_INT32 w, Q_INT32 h) +{ + if (m_paintdev) + return m_paintdev->createThumbnail(w, h); + else + return QImage(); +} + + +Q_INT32 KisPaintLayer::x() const { + if (m_paintdev) + return m_paintdev->getX(); + else return 0; +} + +void KisPaintLayer::setX(Q_INT32 x) +{ + if (m_paintdev) + m_paintdev->setX(x); +} + +Q_INT32 KisPaintLayer::y() const { + if (m_paintdev) + return m_paintdev->getY(); + else + return 0; +} + +void KisPaintLayer::setY(Q_INT32 y) { + if (m_paintdev) + m_paintdev->setY(y); +} + +QRect KisPaintLayer::extent() const { + if (m_paintdev) + return m_paintdev->extent(); + else + return QRect(); +} + +QRect KisPaintLayer::exactBounds() const { + if (m_paintdev) + return m_paintdev->exactBounds(); + else + return QRect(); +} + +void KisPaintLayer::removeMask() { + if (!hasMask()) + return; + + m_mask->setParentLayer(0); + m_mask = 0; + m_maskAsSelection = 0; + setDirty(); + + emit sigMaskInfoChanged(); +} + +// ### XXX Do we apply the mask 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_maskAsSelection, 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_mask; + + kdDebug() << k_funcinfo << endl; + // Grey8 nicely fits our needs of being intuitively comparable to other apps' + // mask layer interfaces. It does have an alpha component though, which is a bit + // less appropriate in this context. + m_mask = new KisPaintDevice(KisMetaRegistry::instance()->csRegistry() + ->getColorSpace(KisID("GRAYA"), 0)); + + genericMaskCreationHelper(); + + return m_mask; +} + +// 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_mask = from; // KisPaintDevice(*from); XXX + + genericMaskCreationHelper(); +} + +void KisPaintLayer::createMaskFromSelection(KisSelectionSP from) { + kdDebug() << k_funcinfo << endl; + m_mask = new KisPaintDevice(KisMetaRegistry::instance()->csRegistry() + ->getColorSpace(KisID("GRAYA"), 0)); + m_mask->setParentLayer(this); + + m_maskAsSelection = new KisSelection(); // Anonymous selection is good enough + + // Default pixel is opaque white == don't mask? + Q_UINT8 const defPixel[] = { 255, 255 }; + m_mask->dataManager()->setDefaultPixel(defPixel); + + if (from) { + QRect 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_mask->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_mask; +} + +KisSelectionSP KisPaintLayer::getMaskAsSelection() { + createMask(); + kdDebug() << k_funcinfo << endl; + return m_maskAsSelection; +} + +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 QRect& r) { + KisRectIteratorPixel srcIt = m_mask->createRectIterator(r.x(), r.y(), + r.width(), r.height(), false); + KisRectIteratorPixel dstIt = m_maskAsSelection->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_mask->setParentLayer(this); + + m_maskAsSelection = new KisSelection(); // Anonymous selection is good enough + + // Default pixel is opaque white == don't mask? + Q_UINT8 const defPixel[] = { 255, 255 }; + m_mask->dataManager()->setDefaultPixel(defPixel); + + setDirty(); + emit sigMaskInfoChanged(); +} + +void KisPaintLayer::setDirty(bool propagate) { + if (hasMask()) + convertMaskToSelection(extent()); + super::setDirty(propagate); +} + +void KisPaintLayer::setDirty(const QRect & 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_mask; + public: + KisCreateMaskCommand(const QString& name, KisPaintLayer* layer) + : super(name), m_layer(layer) {} + virtual void execute() { + kdDebug() << k_funcinfo << endl; + if (!m_mask) + m_mask = m_layer->createMask(); + else + m_layer->createMaskFromPaintDevice(m_mask); + } + virtual void unexecute() { + m_layer->removeMask(); + } + }; + + class KisMaskFromSelectionCommand : public KNamedCommand { + typedef KNamedCommand super; + KisPaintLayerSP m_layer; + KisPaintDeviceSP m_maskBefore; + KisPaintDeviceSP m_maskAfter; + KisSelectionSP m_selection; + public: + KisMaskFromSelectionCommand(const QString& name, KisPaintLayer* layer) + : super(name), m_layer(layer) { + if (m_layer->hasMask()) + m_maskBefore = m_layer->getMask(); + else + m_maskBefore = 0; + m_maskAfter = 0; + if (m_layer->paintDevice()->hasSelection()) + m_selection = m_layer->paintDevice()->selection(); + else + m_selection = 0; + } + virtual void execute() { + if (!m_maskAfter) { + m_layer->createMaskFromSelection(m_selection); + m_maskAfter = m_layer->getMask(); + } else { + m_layer->paintDevice()->deselect(); + m_layer->createMaskFromPaintDevice(m_maskAfter); + } + } + virtual void unexecute() { + m_layer->paintDevice()->setSelection(m_selection); + if (m_maskBefore) + m_layer->createMaskFromPaintDevice(m_maskBefore); + else + m_layer->removeMask(); + } + }; + + class KisMaskToSelectionCommand : public KNamedCommand { + typedef KNamedCommand super; + KisPaintLayerSP m_layer; + KisPaintDeviceSP m_mask; + KisSelectionSP m_selection; + public: + KisMaskToSelectionCommand(const QString& name, KisPaintLayer* layer) + : super(name), m_layer(layer) { + m_mask = 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_mask); + } + }; + + class KisRemoveMaskCommand : public KNamedCommand { + typedef KNamedCommand super; + KisPaintLayerSP m_layer; + KisPaintDeviceSP m_mask; + public: + KisRemoveMaskCommand(const QString& name, KisPaintLayer* layer) + : super(name), m_layer(layer) { + m_mask = 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_mask); + } + }; + + class KisApplyMaskCommand : public KNamedCommand { + typedef KNamedCommand super; + KisPaintLayerSP m_layer; + KisPaintDeviceSP m_mask; + KisPaintDeviceSP m_original; + public: + KisApplyMaskCommand(const QString& name, KisPaintLayer* layer) + : super(name), m_layer(layer) { + m_mask = 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_mask); + } + }; +} + +KNamedCommand* KisPaintLayer::createMaskCommand() { + return new KisCreateMaskCommand(i18n("Create Layer Mask"), this); +} + +KNamedCommand* KisPaintLayer::maskFromSelectionCommand() { + return new KisMaskFromSelectionCommand(i18n("Mask From Selection"), this); +} + +KNamedCommand* KisPaintLayer::maskToSelectionCommand() { + 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/krita/core/kis_paint_layer.h b/krita/core/kis_paint_layer.h new file mode 100644 index 00000000..2c4b562f --- /dev/null +++ b/krita/core/kis_paint_layer.h @@ -0,0 +1,156 @@ +/* + * 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 + +public: + KisPaintLayer(KisImage *img, const QString& name, Q_UINT8 opacity, KisPaintDeviceSP dev); + KisPaintLayer(KisImage *img, const QString& name, Q_UINT8 opacity); + KisPaintLayer(KisImage *img, const QString& name, Q_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 Q_INT32 x() const; + virtual void setX(Q_INT32 x); + + virtual Q_INT32 y() const; + virtual void setY(Q_INT32 y); + + virtual QRect extent() const; + virtual QRect exactBounds() const; + + virtual void paintSelection(QImage &img, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h); + virtual void paintSelection(QImage &img, const QRect& scaledImageRect, const QSize& scaledImageSize, const QSize& imageSize); + + virtual void paintMaskInactiveLayers(QImage &img, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h); + + virtual QImage createThumbnail(Q_INT32 w, Q_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 mask, see editMask) + inline KisPaintDeviceSP paintDeviceOrMask() const { + if (hasMask() && editMask()) + return m_mask; + return m_paintdev; + } + + // Mask Layer + + /// Does this layer have a layer mask? + bool hasMask() const { return m_mask != 0; } + // XXX TODO: Make these undo-able! + /// Create a mask if it does not yet exist, and return it + KisPaintDeviceSP createMask(); + /// Convert the from argument to the mask + void createMaskFromPaintDevice(KisPaintDeviceSP from); + /** + * Convert the from selection to a paint device (should convert the getMaskAsSelection + * result back to the mask). Overwrites the current mask, if any. Also removes the selection + */ + void createMaskFromSelection(KisSelectionSP from); + /// Remove the layer mask + void removeMask(); + /// Apply the layer mask to the paint device, this removes the mask afterwards + void applyMask(); + /// Returns the layer mask's device. Creates one if there is currently none + KisPaintDeviceSP getMask(); + /// Returns the layer mask'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* maskFromSelectionCommand(); + /// Undoable, removes the current mask, but converts it to the current selection + KNamedCommand* maskToSelectionCommand(); + /// Undoable version of removeMask + KNamedCommand* removeMaskCommand(); + /// Undoable version of applyMask + KNamedCommand* applyMaskCommand(); + + /// Returns true if the masked part of the mask 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 mask (if there is one). This is so that tools can draw on the mask + * 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 QRect & rect, bool propagate = true); + + // KisLayerSupportsIndirectPainting + virtual KisLayer* layer() { return this; } +signals: + /// When the mask is created/destroyed or the editmask or rendermask is changed + void sigMaskInfoChanged(); + +private: + void convertMaskToSelection(const QRect& r); + void genericMaskCreationHelper(); + KisPaintDeviceSP m_paintdev; + // Layer mask related: + // XXX It would be nice to merge the next 2 devices... + KisPaintDeviceSP m_mask; // The mask that we can edit and display easily + KisSelectionSP m_maskAsSelection; // The mask as selection, to apply and render easily + bool m_renderMask; + bool m_editMask; +}; + +typedef KSharedPtr KisPaintLayerSP; + +#endif // KIS_PAINT_LAYER_H_ + diff --git a/krita/core/kis_painter.cc b/krita/core/kis_painter.cc new file mode 100644 index 00000000..8086696f --- /dev/null +++ b/krita/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 "qbrush.h" +#include "qfontinfo.h" +#include "qfontmetrics.h" +#include "qpen.h" +#include "qregion.h" +#include "qwmatrix.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 QString& 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; +} + + +QRect KisPainter::dirtyRect() { + QRect r = m_dirtyRect; + m_dirtyRect = QRect(); + return r; +} + +void KisPainter::bitBlt(Q_INT32 dx, Q_INT32 dy, + const KisCompositeOp& op, + KisPaintDeviceSP srcdev, + Q_UINT8 opacity, + Q_INT32 sx, Q_INT32 sy, + Q_INT32 sw, Q_INT32 sh) +{ + if (srcdev == 0) { + return; + } + + QRect srcRect = QRect(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(QRect(dx, dy, sw, sh)); + + KisColorSpace * srcCs = srcdev->colorSpace(); + + Q_INT32 dstY = dy; + Q_INT32 srcY = sy; + Q_INT32 rowsRemaining = sh; + + while (rowsRemaining > 0) { + + Q_INT32 dstX = dx; + Q_INT32 srcX = sx; + Q_INT32 columnsRemaining = sw; + Q_INT32 numContiguousDstRows = m_device->numContiguousRows(dstY, dstX, dstX + sw - 1); + Q_INT32 numContiguousSrcRows = srcdev->numContiguousRows(srcY, srcX, srcX + sw - 1); + + Q_INT32 rows = QMIN(numContiguousDstRows, numContiguousSrcRows); + rows = QMIN(rows, rowsRemaining); + + while (columnsRemaining > 0) { + + Q_INT32 numContiguousDstColumns = m_device->numContiguousColumns(dstX, dstY, dstY + rows - 1); + Q_INT32 numContiguousSrcColumns = srcdev->numContiguousColumns(srcX, srcY, srcY + rows - 1); + + Q_INT32 columns = QMIN(numContiguousDstColumns, numContiguousSrcColumns); + columns = QMIN(columns, columnsRemaining); + + Q_INT32 srcRowStride = srcdev->rowStride(srcX, srcY); + //const Q_UINT8 *srcData = srcdev->pixel(srcX, srcY); + KisHLineIteratorPixel srcIt = srcdev->createHLineIterator(srcX, srcY, columns, false); + const Q_UINT8 *srcData = srcIt.rawData(); + + //Q_UINT8 *dstData = m_device->writablePixel(dstX, dstY); + Q_INT32 dstRowStride = m_device->rowStride(dstX, dstY); + KisHLineIteratorPixel dstIt = m_device->createHLineIterator(dstX, dstY, columns, true); + Q_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(Q_INT32 dx, Q_INT32 dy, + const KisCompositeOp &op, + KisPaintDeviceSP srcdev, + KisSelectionSP seldev, + Q_UINT8 opacity, + Q_INT32 sx, Q_INT32 sy, + Q_INT32 sw, Q_INT32 sh) +{ + // Better use a probablistic method than a too slow one + if (seldev->isProbablyTotallyUnselected(QRect(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(Q_INT32 dx, Q_INT32 dy, + const KisCompositeOp &op, + KisPaintDeviceSP srcdev, + KisPaintDeviceSP seldev, + Q_UINT8 opacity, + Q_INT32 sx, Q_INT32 sy, + Q_INT32 sw, Q_INT32 sh) + +{ + if (srcdev == 0) return; + + if (seldev == 0) return; + + if (m_device == 0) return; + + + QRect srcRect = QRect(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(QRect(dx, dy, sw, sh)); + + KisColorSpace * srcCs = srcdev->colorSpace(); + + Q_INT32 dstY = dy; + Q_INT32 srcY = sy; + Q_INT32 rowsRemaining = sh; + + while (rowsRemaining > 0) { + + Q_INT32 dstX = dx; + Q_INT32 srcX = sx; + Q_INT32 columnsRemaining = sw; + Q_INT32 numContiguousDstRows = m_device->numContiguousRows(dstY, dstX, dstX + sw - 1); + Q_INT32 numContiguousSrcRows = srcdev->numContiguousRows(srcY, srcX, srcX + sw - 1); + Q_INT32 numContiguousSelRows = seldev->numContiguousRows(dstY, dstX, dstX + sw - 1); + + Q_INT32 rows = QMIN(numContiguousDstRows, numContiguousSrcRows); + rows = QMIN(numContiguousSelRows, rows); + rows = QMIN(rows, rowsRemaining); + + while (columnsRemaining > 0) { + + Q_INT32 numContiguousDstColumns = m_device->numContiguousColumns(dstX, dstY, dstY + rows - 1); + Q_INT32 numContiguousSrcColumns = srcdev->numContiguousColumns(srcX, srcY, srcY + rows - 1); + Q_INT32 numContiguousSelColumns = seldev->numContiguousColumns(dstX, dstY, dstY + rows - 1); + + Q_INT32 columns = QMIN(numContiguousDstColumns, numContiguousSrcColumns); + columns = QMIN(numContiguousSelColumns, columns); + columns = QMIN(columns, columnsRemaining); + + //Q_UINT8 *dstData = m_device->writablePixel(dstX, dstY); + Q_INT32 dstRowStride = m_device->rowStride(dstX, dstY); + KisHLineIteratorPixel dstIt = m_device->createHLineIterator(dstX, dstY, columns, true); + Q_UINT8 *dstData = dstIt.rawData(); + + //const Q_UINT8 *srcData = srcdev->pixel(srcX, srcY); + Q_INT32 srcRowStride = srcdev->rowStride(srcX, srcY); + KisHLineIteratorPixel srcIt = srcdev->createHLineIterator(srcX, srcY, columns, false); + const Q_UINT8 *srcData = srcIt.rawData(); + + //const Q_UINT8 *selData = seldev->pixel(dstX, dstY); + Q_INT32 selRowStride = seldev->rowStride(dstX, dstY); + KisHLineIteratorPixel selIt = seldev->createHLineIterator(dstX, dstY, columns, false); + const Q_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(Q_INT32 dx, Q_INT32 dy, + const KisCompositeOp& op, + KisPaintDeviceSP srcdev, + Q_UINT8 opacity, + Q_INT32 sx, Q_INT32 sy, + Q_INT32 sw, Q_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 mask for the actual polygon coverage. + + KisPaintDeviceSP polygon = new KisPaintDevice(m_device->colorSpace(), "polygon"); + Q_CHECK_PTR(polygon); + + KisFillPainter fillPainter(polygon); + QRect 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); + + QRect 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/krita/core/kis_painter.h b/krita/core/kis_painter.h new file mode 100644 index 00000000..fa8de088 --- /dev/null +++ b/krita/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 QRect; +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 Qt + * itself, where you have QPainter and QPaintDevice. + * + * 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 QString& customName = QString::null); + + /// 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(Q_INT32 dx, Q_INT32 dy, + const KisCompositeOp& op, + KisPaintDeviceSP src, + Q_INT32 sx, Q_INT32 sy, + Q_INT32 sw, Q_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(Q_INT32 dx, Q_INT32 dy, + const KisCompositeOp& op, + KisPaintDeviceSP src, + Q_UINT8 opacity, + Q_INT32 sx, Q_INT32 sy, + Q_INT32 sw, Q_INT32 sh); + + /** + * A version of bitBlt that renders using an external mask, ignoring + * the src device's own selection, if it has one. + */ + void bltMask(Q_INT32 dx, Q_INT32 dy, + const KisCompositeOp &op, + KisPaintDeviceSP src, + KisPaintDeviceSP selMask, + Q_UINT8 opacity, + Q_INT32 sx, Q_INT32 sy, + Q_INT32 sw, Q_INT32 sh); + + /** + * A version of bitBlt that renders using an external selection mask, ignoring + * the src device's own selection, if it has one. + */ + void bltSelection(Q_INT32 dx, Q_INT32 dy, + const KisCompositeOp &op, + KisPaintDeviceSP src, + KisSelectionSP selMask, + Q_UINT8 opacity, + Q_INT32 sx, Q_INT32 sy, + Q_INT32 sw, Q_INT32 sh); + + + /** + * A version of bitBlt that renders using the src device's selection mask, if it has one. + */ + void bltSelection(Q_INT32 dx, Q_INT32 dy, + const KisCompositeOp &op, + KisPaintDeviceSP src, + Q_UINT8 opacity, + Q_INT32 sx, Q_INT32 sy, + Q_INT32 sw, Q_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! + */ + QRect dirtyRect(); + + /** + * Add the r to the current dirty rect, and return the dirtyRect after adding r to it. + */ + QRect addDirtyRect(QRect r) { m_dirtyRect |= r; return m_dirtyRect; } + + + + /** + * Paint a line that connects the dots in points + */ + void paintPolyline(const QValueVector &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(Q_UINT8 opacity) { m_opacity = opacity; } + /// Returns the opacity that is used in painting + Q_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; + + QRect 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; + Q_UINT8 m_opacity; + KisCompositeOp m_compositeOp; + KisFilterSP m_filter; + KisPaintOp * m_paintOp; + double m_pressure; + bool m_cancelRequested; + Q_INT32 m_pixelSize; + KisColorSpace * m_colorSpace; + KisProfile * m_profile; + KisPaintDeviceSP m_dab; + bool m_varyBrushSpacingWithPressureWhenDrawingALine; + +}; + + +#endif // KIS_PAINTER_H_ + diff --git a/krita/core/kis_paintop.cc b/krita/core/kis_paintop.cc new file mode 100644 index 00000000..4030e931 --- /dev/null +++ b/krita/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 "qwidget.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 mask) { + return computeDab(mask, m_painter->device()->colorSpace()); +} + +KisPaintDeviceSP KisPaintOp::computeDab(KisAlphaMaskSP mask, 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(); + + Q_INT32 pixelSize = colorSpace->pixelSize(); + + Q_INT32 maskWidth = mask->width(); + Q_INT32 maskHeight = mask->height(); + + // Convert the kiscolor to the right colorspace. + kc.convertTo(colorSpace); + + KisHLineIteratorPixel hiter = m_dab->createHLineIterator(0, 0, maskWidth, true); + for (int y = 0; y < maskHeight; y++) + { + int x=0; + while(! hiter.isDone()) + { + // XXX: Set mask + colorSpace->setAlpha(kc.data(), mask->alphaAt(x++, y), 1); + memcpy(hiter.rawData(), kc.data(), pixelSize); + ++hiter; + } + hiter.nextRow(); + } + + return m_dab; +} + +void KisPaintOp::splitCoordinate(double coordinate, Q_INT32 *whole, double *fraction) +{ + Q_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(QWidget* /*parent*/, const KisInputDevice& /*inputDevice*/) { return 0; } diff --git a/krita/core/kis_paintop.h b/krita/core/kis_paintop.h new file mode 100644 index 00000000..6a6efddc --- /dev/null +++ b/krita/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 QWidget; + +/** + * 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 mask); + virtual KisPaintDeviceSP computeDab(KisAlphaMaskSP mask, KisColorSpace *cs); + + + /** + * Split the coordinate into whole + fraction, where fraction is always >= 0. + */ + virtual void splitCoordinate(double coordinate, Q_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(QWidget *parent) { Q_UNUSED(parent); } + virtual ~KisPaintOpSettings() {} + + virtual QWidget *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 QString 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(QWidget* parent, const KisInputDevice& inputDevice); + +}; +#endif // KIS_PAINTOP_H_ diff --git a/krita/core/kis_paintop_registry.cc b/krita/core/kis_paintop_registry.cc new file mode 100644 index 00000000..0ba7b5f3 --- /dev/null +++ b/krita/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(QString::fromLatin1("Krita/Paintop"), + QString::fromLatin1("(Type == 'Service') and " + "([X-Krita-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, QStringList(), &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 QString & id, const KisPaintOpSettings * settings, KisPainter * painter) const +{ + return paintOp(KisID(id, ""), settings, painter); +} + +KisPaintOpSettings * KisPaintOpRegistry::settings(const KisID& id, QWidget * parent, const KisInputDevice& inputDevice) const +{ + KisPaintOpFactory* f = get(id); + if (f) + return f->settings( parent, 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); + +} + +QString 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/krita/core/kis_paintop_registry.h b/krita/core/kis_paintop_registry.h new file mode 100644 index 00000000..c544a601 --- /dev/null +++ b/krita/core/kis_paintop_registry.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_PAINTOP_REGISTRY_H_ +#define KIS_PAINTOP_REGISTRY_H_ + +#include + +#include "kis_types.h" +#include "kis_generic_registry.h" +#include + +class QWidget; +class QStringList; + +class KisPaintOp; +class KisPaintOpSettings; +class KisPainter; +class KisColorSpace; +class KisInputDevice; + +class KRITACORE_EXPORT KisPaintOpRegistry : public QObject, public KisGenericRegistry +{ + + Q_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 QString& 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 parent as widget parent. Returns 0 if there + * are no settings available for the given device. + */ + KisPaintOpSettings * settings(const KisID& id, QWidget * parent, 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 + QString 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/krita/core/kis_palette.cc b/krita/core/kis_palette.cc new file mode 100644 index 00000000..ad39eed5 --- /dev/null +++ b/krita/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 QImage * img, Q_INT32 nColors, const QString & name) + : super(QString("")), + 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, Q_INT32 nColors, const QString & name) + : super(QString("")), + 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, Q_INT32 nColors, const QString & name) + : super(QString("")), + m_name(name) +{ + Q_ASSERT(nColors > 0); + Q_ASSERT(gradient != 0); + + double dx, cur_x; + QColor c; + Q_INT32 i; + Q_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 QString& 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() +{ + QFile file(filename()); + file.open(IO_ReadOnly); + m_data = file.readAll(); + file.close(); + return init(); +} + + +bool KisPalette::save() +{ + QFile file(filename()); + if (!file.open(IO_WriteOnly | IO_Truncate)) { + return false; + } + + QTextStream 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); + QColor 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; +} + +QImage KisPalette::img() +{ + return m_img; +} + +Q_INT32 KisPalette::nColors() +{ + return m_colors.count(); +} + +bool KisPalette::init() +{ + enumPaletteType format = FORMAT_UNKNOWN; + + QString s = QString::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! + Q_UINT32 index = 0; + + QStringList lines = QStringList::split("\n", s); + + if (lines.size() < 3) { + return false; + } + + QString entry, channel, columns; + QStringList c; + Q_INT32 r, g, b; + QColor 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 (Q_UINT32 i = index; i < lines.size(); i++) { + if (lines[i].startsWith("#")) { + m_comment += lines[i].mid(1).stripWhiteSpace() + " "; + } + else if (!lines[i].isEmpty()) + { + QStringList a = QStringList::split(" ", lines[i].replace(QChar('\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 = QColor(r, g, b); + e.color = color; + + QString 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) +{ + QValueVector::iterator it = m_colors.begin(); + QValueVector::iterator end = m_colors.end(); + + while (it != end) { + if ((*it) == c) { + m_colors.erase(it); + return; + } + ++it; + } +} + +KisPaletteEntry KisPalette::getColor(Q_UINT32 index) +{ + return m_colors[index]; +} + +#include "kis_palette.moc" diff --git a/krita/core/kis_palette.h b/krita/core/kis_palette.h new file mode 100644 index 00000000..5d7d02c9 --- /dev/null +++ b/krita/core/kis_palette.h @@ -0,0 +1,112 @@ +/* + * 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 QPoint; +class QPixmap; +class KisPaintDevice; + +struct KisPaletteEntry { + QColor color; + QString 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 + +public: + /** + * Create a palette from the colours in an image + */ + KisPalette(const QImage * img, Q_INT32 nColors, const QString & name); + + /** + * Create a palette from the colours in a paint device + */ + KisPalette(const KisPaintDeviceSP device, Q_INT32 nColors, const QString & name); + + /** + * Create a palette from the colours in a gradient + */ + KisPalette(const KisGradient * gradient, Q_INT32 nColors, const QString & name); + + /** + * Load a palette from a file. This can be a Gimp + * palette, a RIFF palette or a Photoshop palette. + */ + KisPalette(const QString& 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 QImage img(); + + +public: + + void add(const KisPaletteEntry &); + void remove(const KisPaletteEntry &); + KisPaletteEntry getColor(Q_UINT32 index); + Q_INT32 nColors(); + +private: + bool init(); + +private: + + QByteArray m_data; + bool m_ownData; + QImage m_img; + QString m_name; + QString m_comment; + Q_INT32 m_columns; + QValueVector m_colors; + +}; +#endif // KIS_PALETTE_ + diff --git a/krita/core/kis_part_layer_iface.h b/krita/core/kis_part_layer_iface.h new file mode 100644 index 00000000..b324c975 --- /dev/null +++ b/krita/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 QString &name, Q_UINT8 opacity) + : super(img, name, opacity) {} + virtual KisPaintDeviceSP prepareProjection(KisPaintDeviceSP projection, const QRect& r) = 0; + virtual bool saveToXML(QDomDocument doc, QDomElement elem) = 0; +}; + +#endif // KIS_PART_IFACE_LAYER_IFACE_ diff --git a/krita/core/kis_pattern.cc b/krita/core/kis_pattern.cc new file mode 100644 index 00000000..db6ae0a1 --- /dev/null +++ b/krita/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 { + Q_UINT32 header_size; /* header_size = sizeof (PatternHeader) + brush name */ + Q_UINT32 version; /* pattern file version # */ + Q_UINT32 width; /* width of pattern */ + Q_UINT32 height; /* height of pattern */ + Q_UINT32 bytes; /* depth of pattern in bytes : 1, 2, 3 or 4*/ + Q_UINT32 magic_number; /* GIMP brush magic number */ + }; + + // Yes! This is _NOT_ what my pat.txt file says. It's really not 'GIMP', but 'GPAT' + Q_UINT32 const GimpPatternMagic = (('G' << 24) + ('P' << 16) + ('A' << 8) + ('T' << 0)); +} + +KisPattern::KisPattern(const QString& 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->convertToQImage(0, x, y, w, h)); + setName(image->name()); +} + +KisPattern::~KisPattern() +{ +} + +bool KisPattern::load() +{ + if (!m_hasFile) + return true; + + QFile file(filename()); + file.open(IO_ReadOnly); + QByteArray data = file.readAll(); + if (!data.isEmpty()) { + Q_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() +{ + QFile file(filename()); + file.open(IO_WriteOnly | IO_Truncate); + + QTextStream 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; + QCString utf8Name = name().utf8(); + char const* name = utf8Name.data(); + int nameLength = qstrlen(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); + + QByteArray 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 (Q_INT32 y = 0; y < height(); y++) { + for (Q_INT32 x = 0; x < width(); x++) { + // RGBA only + QRgb pixel = m_img.pixel(x,y); + bytes[k++] = static_cast(qRed(pixel)); + bytes[k++] = static_cast(qGreen(pixel)); + bytes[k++] = static_cast(qBlue(pixel)); + bytes[k++] = static_cast(qAlpha(pixel)); + } + } + + wrote = file.writeBlock(bytes); + if (wrote == -1) + return false; + + file.close(); + + return true; +} + +QImage KisPattern::img() +{ + return m_img; +} + +bool KisPattern::init() +{ + // load Gimp patterns + GimpPatternHeader bh; + Q_INT32 k; + QValueVector 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 + Q_INT32 val; + + for (Q_UINT32 y = 0; y < bh.height; y++) { + for (Q_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, qRgb(val, val, val)); + m_img.setAlphaBuffer(false); + } + } + } else if (bh.bytes == 2) { + // Grayscale + A + Q_INT32 val; + Q_INT32 alpha; + for (Q_UINT32 y = 0; y < bh.height; y++) { + for (Q_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, qRgba(val, val, val, alpha)); + m_img.setAlphaBuffer(true); + } + } + } else if (bh.bytes == 3) { + // RGB without alpha + for (Q_UINT32 y = 0; y < bh.height; y++) { + for (Q_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, qRgb(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 (Q_UINT32 y = 0; y < bh.height; y++) { + for (Q_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, qRgba(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 + QMap::const_iterator it = m_colorspaces.find(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->convertFromQImage(m_img,""); + + m_colorspaces[colorSpace->id().id()] = layer; + return layer; +} + +Q_INT32 KisPattern::width() const +{ + return m_width; +} + +void KisPattern::setWidth(Q_INT32 w) +{ + m_width = w; +} + +Q_INT32 KisPattern::height() const +{ + return m_height; +} + +void KisPattern::setHeight(Q_INT32 h) +{ + m_height = h; +} + +void KisPattern::setImage(const QImage& 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/krita/core/kis_pattern.h b/krita/core/kis_pattern.h new file mode 100644 index 00000000..4b5868f3 --- /dev/null +++ b/krita/core/kis_pattern.h @@ -0,0 +1,79 @@ +/* + * 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 QPoint; +class QImage; +class KisColorSpace; +class KisPaintDevice; + +class KisPattern : public KisResource { + typedef KisResource super; + Q_OBJECT + +public: + KisPattern(const QString& file); + KisPattern(KisPaintDevice* image, int x, int y, int w, int h); + virtual ~KisPattern(); + + virtual bool load(); + virtual bool save(); + virtual QImage img(); + + /** + * returns a KisPaintDeviceSP made with colorSpace as the ColorSpace strategy + * for use in the fill painter. + **/ + KisPaintDeviceSP image(KisColorSpace * colorSpace); + + Q_INT32 width() const; + Q_INT32 height() const; + + void setImage(const QImage& img); + + KisPattern* clone() const; + +protected: + void setWidth(Q_INT32 w); + void setHeight(Q_INT32 h); + +private: + bool init(); + +private: + QByteArray m_data; + QImage m_img; + QMap m_colorspaces; + bool m_hasFile; + + Q_INT32 m_width; + Q_INT32 m_height; +}; + +#endif + diff --git a/krita/core/kis_perspective_grid.cpp b/krita/core/kis_perspective_grid.cpp new file mode 100644 index 00000000..d9b0e800 --- /dev/null +++ b/krita/core/kis_perspective_grid.cpp @@ -0,0 +1,100 @@ +/* + * This file is part of Krita + * + * 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::contains(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( QValueList::const_iterator it = begin(); it != end(); ++it) + { + delete *it; + } + m_subGrids.clear(); +} + +KisSubPerspectiveGrid* KisPerspectiveGrid::gridAt(KisPoint p) +{ + for( QValueList::const_iterator it = begin(); it != end(); ++it) + { + if( (*it)->contains(p) ) + { + return *it; + } + } + return 0; +} + diff --git a/krita/core/kis_perspective_grid.h b/krita/core/kis_perspective_grid.h new file mode 100644 index 00000000..76021a6c --- /dev/null +++ b/krita/core/kis_perspective_grid.h @@ -0,0 +1,107 @@ +/* + * This file is part of Krita + * + * 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 contains(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 QValueList::const_iterator begin() const { return m_subGrids.begin(); } + inline QValueList::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: + QValueList m_subGrids; +}; + +#endif diff --git a/krita/core/kis_perspective_math.cpp b/krita/core/kis_perspective_math.cpp new file mode 100644 index 00000000..eadbab8b --- /dev/null +++ b/krita/core/kis_perspective_math.cpp @@ -0,0 +1,546 @@ +/* + * This file is part of Krita + * + * 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 QRect& r) +{ + return KisPerspectiveMath::computeMatrixTransfo(topLeft, topRight, bottomLeft, bottomRight, r.topLeft(), r.topRight(), r.bottomLeft(), r.bottomRight()); +} + +double* KisPerspectiveMath::computeMatrixTransfoFromPerspective(const QRect& r, const KisPoint& topLeft, const KisPoint& topRight, const KisPoint& bottomLeft, const KisPoint& bottomRight) +{ + return KisPerspectiveMath::computeMatrixTransfo(r.topLeft(), r.topRight(), r.bottomLeft(), r.bottomRight(), topLeft, topRight, bottomLeft, bottomRight); +} + diff --git a/krita/core/kis_perspective_math.h b/krita/core/kis_perspective_math.h new file mode 100644 index 00000000..047e571e --- /dev/null +++ b/krita/core/kis_perspective_math.h @@ -0,0 +1,70 @@ +/* + * This file is part of Krita + * + * 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 QRect; + +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 QRect& r); + static double* computeMatrixTransfoFromPerspective(const QRect& 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/krita/core/kis_perspectivetransform_worker.cpp b/krita/core/kis_perspectivetransform_worker.cpp new file mode 100644 index 00000000..bb98b3bf --- /dev/null +++ b/krita/core/kis_perspectivetransform_worker.cpp @@ -0,0 +1,121 @@ +/* + * This file is part of Krita + * + * 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) + +{ + QRect 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/krita/core/kis_perspectivetransform_worker.h b/krita/core/kis_perspectivetransform_worker.h new file mode 100644 index 00000000..2f53625f --- /dev/null +++ b/krita/core/kis_perspectivetransform_worker.h @@ -0,0 +1,52 @@ +/* + * This file is part of Krita + * + * 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: + Q_INT32 m_progressTotalSteps; + Q_INT32 m_lastProgressReport; + Q_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]; + QRect m_r; +}; + +#endif diff --git a/krita/core/kis_point.h b/krita/core/kis_point.h new file mode 100644 index 00000000..ee5dba78 --- /dev/null +++ b/krita/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 QPoint& 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 qRound(x()); } + int roundY() const { return qRound(y()); } + + QPoint floorQPoint() const { return QPoint(static_cast(x()), static_cast(y())); } + QPoint roundQPoint() const { return QPoint(qRound(x()), qRound(y())); } +}; + +typedef QValueVector vKisPoint; + +#endif // KIS_POINT_H_ + diff --git a/krita/core/kis_random_accessor.cpp b/krita/core/kis_random_accessor.cpp new file mode 100644 index 00000000..3d538453 --- /dev/null +++ b/krita/core/kis_random_accessor.cpp @@ -0,0 +1,58 @@ +/* + * This file is part of the Krita 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, Q_INT32 x, Q_INT32 y, Q_INT32 offsetx, Q_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(Q_INT32 x, Q_INT32 y) +{ + m_accessor->moveTo(x - m_offsetx, y - m_offsety); +} + +Q_UINT8* KisRandomAccessor::rawData() const +{ + return m_accessor->rawData(); +} + +const Q_UINT8* KisRandomAccessor::oldRawData() const +{ + return m_accessor->oldRawData(); +} + +KisRandomAccessorPixel::KisRandomAccessorPixel(KisTiledDataManager *ktm, KisTiledDataManager *ktmselect, Q_INT32 x, Q_INT32 y, Q_INT32 offsetx, Q_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/krita/core/kis_random_accessor.h b/krita/core/kis_random_accessor.h new file mode 100644 index 00000000..dddd94b6 --- /dev/null +++ b/krita/core/kis_random_accessor.h @@ -0,0 +1,95 @@ +/* + * This file is part of the Krita 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, Q_INT32 x, Q_INT32 y, Q_INT32 offsetx, Q_INT32 offsety, bool writable); + KisRandomAccessor(const KisRandomAccessor& rhs); + ~KisRandomAccessor(); + public: + /// Move to a given x,y position, fetch tiles and data + void moveTo(Q_INT32 x, Q_INT32 y); + Q_UINT8* rawData() const; + const Q_UINT8* oldRawData() const; + private: + KisTiledRandomAccessorSP m_accessor; + Q_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 Q_UINT8 operator[](int index) const + { return m_underlyingAccessor->rawData()[index]; }; + /** + * Returns the degree of selectedness of the pixel. + */ + inline Q_UINT8 selectedness() const + { + return (m_selectionAccessor) ? *(m_selectionAccessor->rawData()) : MAX_SELECTED; + }; + + /** + * Returns the selectionmask 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 Q_UINT8 * selectionMask() const + { + return ( m_selectionAccessor ) ? m_selectionAccessor->rawData() : 0; + } + + inline void moveTo(Q_INT32 x, Q_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, Q_INT32 x, Q_INT32 y, Q_INT32 offsetx, Q_INT32 offsety, bool writable); + public: + inline void moveTo(Q_INT32 x, Q_INT32 y) { KisRandomAccessor::moveTo(x,y); KisRandomAccessorPixelTrait::moveTo(x,y); } +}; + + +#endif diff --git a/krita/core/kis_random_sub_accessor.cpp b/krita/core/kis_random_sub_accessor.cpp new file mode 100644 index 00000000..3b63f340 --- /dev/null +++ b/krita/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(Q_UINT8* dst) +{ + const Q_UINT8* pixels[4]; + Q_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)qRound( ( 1.0 - hsub) * ( 1.0 - vsub) * 255 ); + m_randomAccessor.moveTo(x, y); + pixels[0] = m_randomAccessor.oldRawData(); + weights[1] = (int)qRound( ( 1.0 - vsub) * hsub * 255 ); + m_randomAccessor.moveTo(x+1, y); + pixels[1] = m_randomAccessor.oldRawData(); + weights[2] = (int)qRound( vsub * ( 1.0 - hsub) * 255 ); + m_randomAccessor.moveTo(x, y+1); + pixels[2] = m_randomAccessor.oldRawData(); + weights[3] = (int)qRound( 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(Q_UINT8* dst) +{ + const Q_UINT8* pixels[4]; + Q_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)qRound( ( 1.0 - hsub) * ( 1.0 - vsub) * 255 ); + m_randomAccessor.moveTo(x, y); + pixels[0] = m_randomAccessor.rawData(); + weights[1] = (int)qRound( ( 1.0 - vsub) * hsub * 255 ); + m_randomAccessor.moveTo(x+1, y); + pixels[1] = m_randomAccessor.rawData(); + weights[2] = (int)qRound( vsub * ( 1.0 - hsub) * 255 ); + m_randomAccessor.moveTo(x, y+1); + pixels[2] = m_randomAccessor.rawData(); + weights[3] = (int)qRound( 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/krita/core/kis_random_sub_accessor.h b/krita/core/kis_random_sub_accessor.h new file mode 100644 index 00000000..7beb7945 --- /dev/null +++ b/krita/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(Q_UINT8* dst); + void sampledRawData(Q_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/krita/core/kis_rect.cc b/krita/core/kis_rect.cc new file mode 100644 index 00000000..892a5e32 --- /dev/null +++ b/krita/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" + +QRect KisRect::qRect() const +{ + return QRect(static_cast(floor(left())), static_cast(floor(top())), static_cast(ceil(right()) - floor(left())), static_cast(ceil(bottom()) - floor(top()))); +} + diff --git a/krita/core/kis_rect.h b/krita/core/kis_rect.h new file mode 100644 index 00000000..268b64eb --- /dev/null +++ b/krita/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 QRect 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 QRect& qr) : super(qr.x(), qr.y(), qr.width(), qr.height()) {} + KisRect(const KoRect& r) : super(r) {} + + /** + * Return the QRect that encloses this KisRect. + */ + QRect qRect() const; + +private: + // Use qRect() which uses ceil() and floor() to return a rectangle + // 'enclosing' the rectangle, whereas toQRect rounds the points. + QRect toQRect() const; +}; + +#endif // KIS_RECT_H_ + diff --git a/krita/core/kis_resource.cc b/krita/core/kis_resource.cc new file mode 100644 index 00000000..256ffae5 --- /dev/null +++ b/krita/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 QString& filename) +{ + m_filename = filename; + m_valid = false; +} + +KisResource::~KisResource() +{ +} + +QString KisResource::filename() const +{ + return m_filename; +} + +void KisResource::setFilename(const QString& filename) +{ + m_filename = filename; +} + +QString KisResource::name() const +{ + return m_name; +} + +void KisResource::setName(const QString& 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/krita/core/kis_resource.h b/krita/core/kis_resource.h new file mode 100644 index 00000000..d798d3cd --- /dev/null +++ b/krita/core/kis_resource.h @@ -0,0 +1,83 @@ +/* + * 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 Krita 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 QObject { + typedef QObject super; + Q_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 QString& 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 QImage representing this resource. This image could be null. + */ + virtual QImage img() = 0; + +public: + QString filename() const; + void setFilename(const QString& filename); + QString name() const; + void setName(const QString& name); + bool valid() const; + void setValid(bool valid); + +private: + KisResource(const KisResource&); + KisResource& operator=(const KisResource&); + +private: + QString m_name; + QString m_filename; + bool m_valid; +}; + +#endif // KIS_RESOURCE_H_ + diff --git a/krita/core/kis_rotate_visitor.cc b/krita/core/kis_rotate_visitor.cc new file mode 100644 index 00000000..4e703633 --- /dev/null +++ b/krita/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 { + QRect 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); + QRect 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); + + QRect 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()); + + Q_INT32 pixelSize = src->pixelSize(); + QRect r = src->exactBounds(); + Q_INT32 x = 0; + + for (Q_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"); + + Q_INT32 pixelSize = src->pixelSize(); + QRect r = src->exactBounds(); + Q_INT32 x = 0; + + for (Q_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()); + + Q_INT32 pixelSize = src->pixelSize(); + QRect r = src->exactBounds(); + + for (Q_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; + } + + QRect 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((Q_INT32)(dst->getX() + centreOfRotation.x() - rotatedCentreOfRotation.x())); + dst->setY((Q_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()); + + QRect r = src->exactBounds(); + + double displacement; + Q_INT32 displacementInt; + double weight; + + for (Q_INT32 y = r.top(); y <= r.bottom(); y++) { + + //calculate displacement + displacement = -y * shearX; + + displacementInt = (Q_INT32)(floor(displacement)); + weight = displacement - displacementInt; + + Q_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 Q_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()); + + QRect r = src->exactBounds(); + + double displacement; + Q_INT32 displacementInt; + double weight; + + for (Q_INT32 x = r.left(); x <= r.right(); x++) { + + //calculate displacement + displacement = x * shearY; + + displacementInt = (Q_INT32)(floor(displacement)); + weight = displacement - displacementInt; + + Q_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 Q_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(Q_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++; + Q_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/krita/core/kis_rotate_visitor.h b/krita/core/kis_rotate_visitor.h new file mode 100644 index 00000000..19db35f4 --- /dev/null +++ b/krita/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 QRect; +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(Q_INT32 totalSteps); + void incrementProgress(); + void setProgressDone(); + + KisProgressDisplayInterface *m_progress; + Q_INT32 m_progressStep; + Q_INT32 m_progressTotalSteps; + Q_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/krita/core/kis_scale_visitor.cc b/krita/core/kis_scale_visitor.cc new file mode 100644 index 00000000..424db7c6 --- /dev/null +++ b/krita/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(); + + QRect rect = m_dev -> exactBounds(); + Q_INT32 width = rect.width(); + Q_INT32 height = rect.height(); + m_pixelSize=m_dev -> pixelSize(); + + // compute size of target image + if ( m_sx == 1.0F && m_sy == 1.0F ) { + return; + } + Q_INT32 targetW = QABS( qRound( m_sx * width ) ); + Q_INT32 targetH = QABS( qRound( m_sy * height ) ); + + Q_UINT8* newData = new Q_UINT8[targetW * targetH * m_pixelSize ]; + Q_CHECK_PTR(newData); + + double* weight = new double[ m_pixelSize ]; /* filter calculation variables */ + + Q_UINT8* pel = new Q_UINT8[ m_pixelSize ]; + Q_CHECK_PTR(pel); + + Q_UINT8 *pel2 = new Q_UINT8[ m_pixelSize ]; + Q_CHECK_PTR(pel2); + + bool* bPelDelta = new bool[ m_pixelSize ]; + ContribList *contribX; + ContribList contribY; + const Q_INT32 BLACK_PIXEL=0; + const Q_INT32 WHITE_PIXEL=255; + + + // create intermediate row to hold vertical dst row zoom + Q_UINT8 * tmp = new Q_UINT8[ width * m_pixelSize ]; + Q_CHECK_PTR(tmp); + + //create array of pointers to intermediate rows + Q_UINT8 **tmpRows = new Q_UINT8*[ height ]; + + //create array of pointers to intermediate rows that are actually used simultaneously and allocate memory for the rows + Q_UINT8 **tmpRowsMem; + if(m_sy < 1.0) + { + tmpRowsMem = new Q_UINT8*[ (int)(fwidth / m_sy * 2 + 1) ]; + for(int i = 0; i < (int)(fwidth / m_sy * 2 + 1); i++) + { + tmpRowsMem[i] = new Q_UINT8[ width * m_pixelSize ]; + Q_CHECK_PTR(tmpRowsMem[i]); + } + } + else + { + tmpRowsMem = new Q_UINT8*[ (int)(fwidth * 2 + 1) ]; + for(int i = 0; i < (int)(fwidth * 2 + 1); i++) + { + tmpRowsMem[i] = new Q_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); + } + + QTime starttime = QTime::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 Q_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(qRound(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(qRound(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]; + } + } + + QTime stoptime = QTime::currentTime (); + return; +} + +int KisScaleWorker::calcContrib(ContribList *contrib, double scale, double fwidth, int srcwidth, KisFilterStrategy* filterStrategy, Q_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; + Q_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/krita/core/kis_scale_visitor.h b/krita/core/kis_scale_visitor.h new file mode 100644 index 00000000..e20ba2e0 --- /dev/null +++ b/krita/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: + Q_INT32 m_pixel; + double m_weight; + }; + + class ContribList { + public: + Q_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: + Q_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, Q_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: + + QPtrList 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/krita/core/kis_selected_transaction.cc b/krita/core/kis_selected_transaction.cc new file mode 100644 index 00000000..78430a84 --- /dev/null +++ b/krita/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 QString& 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/krita/core/kis_selected_transaction.h b/krita/core/kis_selected_transaction.h new file mode 100644 index 00000000..7d1182c0 --- /dev/null +++ b/krita/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 QString& 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/krita/core/kis_selection.cc b/krita/core/kis_selection.cc new file mode 100644 index 00000000..9964a355 --- /dev/null +++ b/krita/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->parentLayer() + , KisMetaRegistry::instance()->csRegistry()->getAlpha8() + , (QString("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() +{ +} + +Q_UINT8 KisSelection::selected(Q_INT32 x, Q_INT32 y) +{ + KisHLineIteratorPixel iter = createHLineIterator(x, y, 1, false); + + Q_UINT8 *pix = iter.rawData(); + + return *pix; +} + +void KisSelection::setSelected(Q_INT32 x, Q_INT32 y, Q_UINT8 s) +{ + KisHLineIteratorPixel iter = createHLineIterator(x, y, 1, true); + + Q_UINT8 *pix = iter.rawData(); + + *pix = s; +} + +QImage KisSelection::maskImage() +{ + // If part of a KisAdjustmentLayer, there may be no parent device. + QImage img; + QRect bounds; + if (m_parentPaintDevice) { + + bounds = m_parentPaintDevice->exactBounds(); + bounds = bounds.intersect( m_parentPaintDevice->image()->bounds() ); + img = QImage(bounds.width(), bounds.height(), 32); + } + else { + bounds = QRect( 0, 0, image()->width(), image()->height()); + img = QImage(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()) { + Q_UINT8 s = MAX_SELECTED - *(it.rawData()); + Q_INT32 c = qRgb(s, s, s); + img.setPixel(x2, y2, c); + ++x2; + ++it; + } + it.nextRow(); + } + return img; +} +void KisSelection::select(QRect r) +{ + KisFillPainter painter(this); + KisColorSpace * cs = KisMetaRegistry::instance()->csRegistry()->getRGB8(); + painter.fillRect(r, KisColor(Qt::white, cs), MAX_SELECTED); + Q_INT32 x, y, w, h; + extent(x, y, w, h); +} + +void KisSelection::clear(QRect r) +{ + KisFillPainter painter(this); + KisColorSpace * cs = KisMetaRegistry::instance()->csRegistry()->getRGB8(); + painter.fillRect(r, KisColor(Qt::white, cs), MIN_SELECTED); +} + +void KisSelection::clear() +{ + Q_UINT8 defPixel = MIN_SELECTED; + m_datamanager->setDefaultPixel(&defPixel); + m_datamanager->clear(); +} + +void KisSelection::invert() +{ + Q_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; + } + Q_UINT8 defPixel = MAX_SELECTED - *(m_datamanager->defaultPixel()); + m_datamanager->setDefaultPixel(&defPixel); +} + +bool KisSelection::isTotallyUnselected(QRect r) +{ + if(*(m_datamanager->defaultPixel()) != MIN_SELECTED) + return false; + QRect sr = selectedExactRect(); + return ! r.intersects(sr); +} + +bool KisSelection::isProbablyTotallyUnselected(QRect r) +{ + if(*(m_datamanager->defaultPixel()) != MIN_SELECTED) + return false; + QRect sr = selectedRect(); + return ! r.intersects(sr); +} + + +QRect KisSelection::selectedRect() const +{ + if(*(m_datamanager->defaultPixel()) == MIN_SELECTED || !m_parentPaintDevice) + return extent(); + else + return extent().unite(m_parentPaintDevice->extent()); +} + +QRect 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(QImage img, const QRect& imageRect, const QRegion& uniformRegion) +{ + Q_ASSERT(img.size() == imageRect.size()); + Q_ASSERT(imageRect.contains(uniformRegion.boundingRect())); + + if (img.isNull() || img.size() != imageRect.size() || !imageRect.contains(uniformRegion.boundingRect())) { + return; + } + + if (*m_datamanager->defaultPixel() == MIN_SELECTED) { + + QRegion region = uniformRegion & QRegion(imageRect); + + if (!region.isEmpty()) { + QMemArray rects = region.rects(); + + for (unsigned int i = 0; i < rects.count(); i++) { + QRect r = rects[i]; + + for (Q_INT32 y = 0; y < r.height(); ++y) { + + QRgb *imagePixel = reinterpret_cast(img.scanLine(r.y() - imageRect.y() + y)); + imagePixel += r.x() - imageRect.x(); + + Q_INT32 numPixels = r.width(); + + while (numPixels > 0) { + + QRgb srcPixel = *imagePixel; + Q_UINT8 srcGrey = (qRed(srcPixel) + qGreen(srcPixel) + qBlue(srcPixel)) / 9; + Q_UINT8 srcAlpha = qAlpha(srcPixel); + + srcGrey = UINT8_MULT(srcGrey, srcAlpha); + Q_UINT8 dstAlpha = QMAX(srcAlpha, 192); + + QRgb dstPixel = qRgba(128 + srcGrey, 128 + srcGrey, 165 + srcGrey, dstAlpha); + *imagePixel = dstPixel; + + ++imagePixel; + --numPixels; + } + } + } + } + } +} + +void KisSelection::paintSelection(QImage img, Q_INT32 imageRectX, Q_INT32 imageRectY, Q_INT32 imageRectWidth, Q_INT32 imageRectHeight) +{ + Q_ASSERT(img.size() == QSize(imageRectWidth, imageRectHeight)); + + if (img.isNull() || img.size() != QSize(imageRectWidth, imageRectHeight)) { + return; + } + + QRect imageRect(imageRectX, imageRectY, imageRectWidth, imageRectHeight); + QRect selectionExtent = extent(); + + selectionExtent.setLeft(selectionExtent.left() - 1); + selectionExtent.setTop(selectionExtent.top() - 1); + selectionExtent.setWidth(selectionExtent.width() + 2); + selectionExtent.setHeight(selectionExtent.height() + 2); + + QRegion uniformRegion = QRegion(imageRect); + uniformRegion -= QRegion(selectionExtent); + + if (!uniformRegion.isEmpty()) { + paintUniformSelectionRegion(img, imageRect, uniformRegion); + } + + QRect nonuniformRect = imageRect & selectionExtent; + + if (!nonuniformRect.isEmpty()) { + + const Q_INT32 imageRectOffsetX = nonuniformRect.x() - imageRectX; + const Q_INT32 imageRectOffsetY = nonuniformRect.y() - imageRectY; + + imageRectX = nonuniformRect.x(); + imageRectY = nonuniformRect.y(); + imageRectWidth = nonuniformRect.width(); + imageRectHeight = nonuniformRect.height(); + + const Q_INT32 NUM_SELECTION_ROWS = 3; + + Q_UINT8 *selectionRow[NUM_SELECTION_ROWS]; + + Q_INT32 aboveRowIndex = 0; + Q_INT32 centreRowIndex = 1; + Q_INT32 belowRowIndex = 2; + + selectionRow[aboveRowIndex] = new Q_UINT8[imageRectWidth + 2]; + selectionRow[centreRowIndex] = new Q_UINT8[imageRectWidth + 2]; + selectionRow[belowRowIndex] = new Q_UINT8[imageRectWidth + 2]; + + readBytes(selectionRow[centreRowIndex], imageRectX - 1, imageRectY - 1, imageRectWidth + 2, 1); + readBytes(selectionRow[belowRowIndex], imageRectX - 1, imageRectY, imageRectWidth + 2, 1); + + for (Q_INT32 y = 0; y < imageRectHeight; ++y) { + + Q_INT32 oldAboveRowIndex = aboveRowIndex; + aboveRowIndex = centreRowIndex; + centreRowIndex = belowRowIndex; + belowRowIndex = oldAboveRowIndex; + + readBytes(selectionRow[belowRowIndex], imageRectX - 1, imageRectY + y + 1, imageRectWidth + 2, 1); + + const Q_UINT8 *aboveRow = selectionRow[aboveRowIndex] + 1; + const Q_UINT8 *centreRow = selectionRow[centreRowIndex] + 1; + const Q_UINT8 *belowRow = selectionRow[belowRowIndex] + 1; + + QRgb *imagePixel = reinterpret_cast(img.scanLine(imageRectOffsetY + y)); + imagePixel += imageRectOffsetX; + + for (Q_INT32 x = 0; x < imageRectWidth; ++x) { + + Q_UINT8 centre = *centreRow; + + if (centre != MAX_SELECTED) { + + // this is where we come if the pixels should be blue or bluish + + QRgb srcPixel = *imagePixel; + Q_UINT8 srcGrey = (qRed(srcPixel) + qGreen(srcPixel) + qBlue(srcPixel)) / 9; + Q_UINT8 srcAlpha = qAlpha(srcPixel); + + // Colour influence is proportional to alphaPixel. + srcGrey = UINT8_MULT(srcGrey, srcAlpha); + + QRgb dstPixel; + + if (centre == MIN_SELECTED) { + //this is where we come if the pixels should be blue (or red outline) + + Q_UINT8 left = *(centreRow - 1); + Q_UINT8 right = *(centreRow + 1); + Q_UINT8 above = *aboveRow; + Q_UINT8 below = *belowRow; + + // Stop unselected transparent areas from appearing the same + // as selected transparent areas. + Q_UINT8 dstAlpha = QMAX(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 = qRgba(255, 0, 0, dstAlpha); + } else { + dstPixel = qRgba(128 + srcGrey, 128 + srcGrey, 165 + srcGrey, dstAlpha); + } + } else { + dstPixel = qRgba(UINT8_BLEND(qRed(srcPixel), srcGrey + 128, centre), + UINT8_BLEND(qGreen(srcPixel), srcGrey + 128, centre), + UINT8_BLEND(qBlue(srcPixel), srcGrey + 165, centre), + srcAlpha); + } + + *imagePixel = dstPixel; + } + + aboveRow++; + centreRow++; + belowRow++; + imagePixel++; + } + } + + delete [] selectionRow[aboveRowIndex]; + delete [] selectionRow[centreRowIndex]; + delete [] selectionRow[belowRowIndex]; + } +} + +void KisSelection::paintSelection(QImage img, const QRect& scaledImageRect, const QSize& scaledImageSize, const QSize& imageSize) +{ + if (img.isNull() || scaledImageRect.isEmpty() || scaledImageSize.isEmpty() || imageSize.isEmpty()) { + return; + } + + Q_ASSERT(img.size() == scaledImageRect.size()); + + if (img.size() != scaledImageRect.size()) { + return; + } + + Q_INT32 imageWidth = imageSize.width(); + Q_INT32 imageHeight = imageSize.height(); + + QRect 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; + + QRect 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); + + QRegion uniformRegion = QRegion(scaledImageRect); + uniformRegion -= QRegion(scaledSelectionExtent); + + if (!uniformRegion.isEmpty()) { + paintUniformSelectionRegion(img, scaledImageRect, uniformRegion); + } + + QRect nonuniformRect = scaledImageRect & scaledSelectionExtent; + + if (!nonuniformRect.isEmpty()) { + + const Q_INT32 scaledImageRectXOffset = nonuniformRect.x() - scaledImageRect.x(); + const Q_INT32 scaledImageRectYOffset = nonuniformRect.y() - scaledImageRect.y(); + + const Q_INT32 scaledImageRectX = nonuniformRect.x(); + const Q_INT32 scaledImageRectY = nonuniformRect.y(); + const Q_INT32 scaledImageRectWidth = nonuniformRect.width(); + const Q_INT32 scaledImageRectHeight = nonuniformRect.height(); + + const Q_INT32 imageRowLeft = static_cast(scaledImageRectX / xScale); + const Q_INT32 imageRowRight = static_cast((ceil((scaledImageRectX + scaledImageRectWidth - 1 + 1) / xScale)) - 1); + + const Q_INT32 imageRowWidth = imageRowRight - imageRowLeft + 1; + const Q_INT32 imageRowStride = imageRowWidth + 2; + + const Q_INT32 NUM_SELECTION_ROWS = 3; + + Q_INT32 aboveRowIndex = 0; + Q_INT32 centreRowIndex = 1; + Q_INT32 belowRowIndex = 2; + + Q_INT32 aboveRowSrcY = -3; + Q_INT32 centreRowSrcY = -3; + Q_INT32 belowRowSrcY = -3; + + Q_UINT8 *selectionRows = new Q_UINT8[imageRowStride * NUM_SELECTION_ROWS]; + Q_UINT8 *selectionRow[NUM_SELECTION_ROWS]; + + selectionRow[0] = selectionRows + 1; + selectionRow[1] = selectionRow[0] + imageRowStride; + selectionRow[2] = selectionRow[0] + (2 * imageRowStride); + + for (Q_INT32 y = 0; y < scaledImageRectHeight; ++y) { + + Q_INT32 scaledY = scaledImageRectY + y; + Q_INT32 srcY = (scaledY * imageHeight) / scaledImageSize.height(); + + Q_UINT8 *aboveRow; + Q_UINT8 *centreRow; + Q_UINT8 *belowRow; + + if (srcY - 1 == aboveRowSrcY) { + aboveRow = selectionRow[aboveRowIndex]; + centreRow = selectionRow[centreRowIndex]; + belowRow = selectionRow[belowRowIndex]; + } else if (srcY - 1 == centreRowSrcY) { + + Q_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) { + + Q_INT32 oldAboveRowIndex = aboveRowIndex; + Q_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; + + QRgb *imagePixel = reinterpret_cast(img.scanLine(scaledImageRectYOffset + y)); + imagePixel += scaledImageRectXOffset; + + for (Q_INT32 x = 0; x < scaledImageRectWidth; ++x) { + + Q_INT32 scaledX = scaledImageRectX + x; + Q_INT32 srcX = (scaledX * imageWidth) / scaledImageSize.width(); + + Q_UINT8 centre = *(centreRow + srcX - imageRowLeft); + + if (centre != MAX_SELECTED) { + + // this is where we come if the pixels should be blue or bluish + + QRgb srcPixel = *imagePixel; + Q_UINT8 srcGrey = (qRed(srcPixel) + qGreen(srcPixel) + qBlue(srcPixel)) / 9; + Q_UINT8 srcAlpha = qAlpha(srcPixel); + + // Colour influence is proportional to alphaPixel. + srcGrey = UINT8_MULT(srcGrey, srcAlpha); + + QRgb dstPixel; + + if (centre == MIN_SELECTED) { + //this is where we come if the pixels should be blue (or red outline) + + Q_UINT8 left = *(centreRow + (srcX - imageRowLeft) - 1); + Q_UINT8 right = *(centreRow + (srcX - imageRowLeft) + 1); + Q_UINT8 above = *(aboveRow + (srcX - imageRowLeft)); + Q_UINT8 below = *(belowRow + (srcX - imageRowLeft)); + + // Stop unselected transparent areas from appearing the same + // as selected transparent areas. + Q_UINT8 dstAlpha = QMAX(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 = qRgba(255, 0, 0, dstAlpha); + } else { + dstPixel = qRgba(128 + srcGrey, 128 + srcGrey, 165 + srcGrey, dstAlpha); + } + } else { + dstPixel = qRgba(UINT8_BLEND(qRed(srcPixel), srcGrey + 128, centre), + UINT8_BLEND(qGreen(srcPixel), srcGrey + 128, centre), + UINT8_BLEND(qBlue(srcPixel), srcGrey + 165, centre), + srcAlpha); + } + + *imagePixel = dstPixel; + } + + imagePixel++; + } + } + + delete [] selectionRows; + } +} + +void KisSelection::setDirty(const QRect& rc) +{ + if (m_dirty) + super::setDirty(rc); +} + +void KisSelection::setDirty() +{ + if (m_dirty) + super::setDirty(); +} diff --git a/krita/core/kis_selection.h b/krita/core/kis_selection.h new file mode 100644 index 00000000..959be492 --- /dev/null +++ b/krita/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 parent paint device. The selection will never be bigger than the parent + * paint device. + */ + KisSelection(KisPaintDeviceSP dev); + + /** + * Create a new KisSelection. This selection will not have a parent paint device. + */ + KisSelection(); + + /** + * Copy the selection + */ + KisSelection(const KisSelection& rhs); + + virtual ~KisSelection(); + + // Returns selectedness, or 0 if invalid coordinates + Q_UINT8 selected(Q_INT32 x, Q_INT32 y); + + void setSelected(Q_INT32 x, Q_INT32 y, Q_UINT8 s); + + QImage maskImage(); + + void select(QRect r); + + void invert(); + + void clear(QRect r); + + void clear(); + + /// Tests if the the rect is totally outside the selection + bool isTotallyUnselected(QRect 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(QRect r); + + /** + * Rough, but fastish way of determining the area + * of the tiles used by the selection. + */ + QRect selectedRect() const; + + /** + * Slow, but exact way of determining the rectangle + * that encloses the selection + */ + QRect selectedExactRect() const; + + void paintSelection(QImage img, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h); + void paintSelection(QImage img, const QRect& scaledImageRect, const QSize& scaledImageSize, const QSize& imageSize); + + void startCachingExactRect(); + void stopCachingExactRect(); + + // if the parent 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 QRect & rc); + virtual void setDirty(); + inline KisPaintDeviceSP parentPaintDevice() { return m_parentPaintDevice; } +private: + void paintUniformSelectionRegion(QImage img, const QRect& imageRect, const QRegion& uniformRegion); + +private: + + // We don't want these methods to be used on selections: + void extent(Q_INT32 &x, Q_INT32 &y, Q_INT32 &w, Q_INT32 &h) const + { + KisPaintDevice::extent(x,y,w,h); + } + + QRect extent() const { return KisPaintDevice::extent(); } + + void exactBounds(Q_INT32 &x, Q_INT32 &y, Q_INT32 &w, Q_INT32 &h) const + { + return KisPaintDevice::exactBounds(x,y,w,h); + } + + QRect exactBounds() const + { + return KisPaintDevice::exactBounds(); + } + + QRect exactBoundsOldMethod() const + { + return KisPaintDevice::exactBoundsOldMethod(); + } + + QRect exactBoundsImprovedOldMethod() const + { + return KisPaintDevice::exactBoundsImprovedOldMethod(); + } + + +private: + KisPaintDeviceSP m_parentPaintDevice; + bool m_doCacheExactRect; + QRect m_cachedExactRect; + bool m_dirty; +}; + +#endif // KIS_SELECTION_H_ diff --git a/krita/core/kis_shear_visitor.h b/krita/core/kis_shear_visitor.h new file mode 100644 index 00000000..9a48181e --- /dev/null +++ b/krita/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/krita/core/kis_strategy_move.cc b/krita/core/kis_strategy_move.cc new file mode 100644 index 00000000..bd99349b --- /dev/null +++ b/krita/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 QPoint& 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 QPoint& 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())) { + QPoint pos = original; + QRect 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 = QPoint(dev->x(), dev->y()); + m_dragStart = original; + + dev->setDirty(rc); + } + } +} + +void KisStrategyMove::endDrag(const QPoint& 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 QPoint& pt1, const QPoint& pt2) +{ + startDrag(pt1); + endDrag(pt2); +} + +void KisStrategyMove::simpleMove(Q_INT32 x1, Q_INT32 y1, Q_INT32 x2, Q_INT32 y2) +{ + startDrag(QPoint(x1, y1)); + endDrag(QPoint(x2, y2)); +} + diff --git a/krita/core/kis_strategy_move.h b/krita/core/kis_strategy_move.h new file mode 100644 index 00000000..e3787866 --- /dev/null +++ b/krita/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 QPoint& pos); + void drag(const QPoint& pos); + void endDrag(const QPoint& pos, bool undo = true); + void simpleMove(const QPoint& pt1, const QPoint& pt2); + void simpleMove(Q_INT32 x1, Q_INT32 y1, Q_INT32 x2, Q_INT32 y2); + +private: + KisStrategyMove(const KisStrategyMove&); + KisStrategyMove& operator=(const KisStrategyMove&); + +private: + KisCanvasController *m_controller; + KisCanvasSubject *m_subject; + QRect m_deviceBounds; + QPoint m_dragStart; + QPoint m_layerStart; + QPoint m_layerPosition; + bool m_dragging; +}; + +#endif // KIS_STRATEGY_MOVE_H_ + diff --git a/krita/core/kis_substrate.h b/krita/core/kis_substrate.h new file mode 100644 index 00000000..96207747 --- /dev/null +++ b/krita/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? + Q_UINT8 r; //.Red component of reflectivity + Q_UINT8 g; // Green component of reflectivity + Q_UINT8 b; // Blue component of reflectivity + Q_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 QRect & 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 QRect & 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/krita/core/kis_thread.h b/krita/core/kis_thread.h new file mode 100644 index 00000000..f26ebf8b --- /dev/null +++ b/krita/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 QThread 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 QThread { + +public: + + /** + * Create a new KisThread with the canceled state set to false + */ + KisThread() : QThread(), 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/krita/core/kis_thread_pool.cc b/krita/core/kis_thread_pool.cc new file mode 100644 index 00000000..2f80a0ae --- /dev/null +++ b/krita/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.findRef(thread); + if (i >= 0) { + t = m_threads.take(i); + m_numberOfQueuedThreads--; + } else { + i = m_runningThreads.findRef(thread); + if (i >= 0) { + t = m_runningThreads.take(i); + m_numberOfRunningThreads--; + } + else { + i = m_oldThreads.findRef(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/krita/core/kis_thread_pool.h b/krita/core/kis_thread_pool.h new file mode 100644 index 00000000..069cb5a5 --- /dev/null +++ b/krita/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&); + + QMutex m_poolMutex; + int m_numberOfRunningThreads; + int m_numberOfQueuedThreads; + int m_maxThreads; + int m_wait; + QPtrList m_threads; + QPtrList m_runningThreads; + QPtrList m_oldThreads; + + static KisThreadPool * m_singleton; +}; + + +#endif diff --git a/krita/core/kis_transaction.cc b/krita/core/kis_transaction.cc new file mode 100644 index 00000000..10df1a8e --- /dev/null +++ b/krita/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: + QString m_name; + KisPaintDeviceSP m_device; + KisMementoSP m_memento; + +}; + +KisTransaction::KisTransaction(const QString& 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); + + QRect rc; + Q_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->parentLayer(); + if (l) l->setDirty(rc); +} + +void KisTransaction::unexecute() +{ + Q_ASSERT(m_private->m_memento != 0); + m_private->m_device->rollback(m_private->m_memento); + + QRect rc; + Q_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->parentLayer(); + if (l) l->setDirty(rc); + +} + +void KisTransaction::unexecuteNoUpdate() +{ + Q_ASSERT(m_private->m_memento != 0); + + m_private->m_device->rollback(m_private->m_memento); +} + +QString KisTransaction::name() const +{ + return m_private->m_name; +} diff --git a/krita/core/kis_transaction.h b/krita/core/kis_transaction.h new file mode 100644 index 00000000..0865c59b --- /dev/null +++ b/krita/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 QRect; +class KisTransactionPrivate; + +class KisTransaction : public KCommand { +public: + KisTransaction(const QString& name, KisPaintDeviceSP device); + virtual ~KisTransaction(); + +public: + virtual void execute(); + virtual void unexecute(); + virtual void unexecuteNoUpdate(); + virtual QString name() const; +private: + KisTransactionPrivate * m_private; +}; + +#endif // KIS_TILE_COMMAND_H_ + diff --git a/krita/core/kis_transform_visitor.h b/krita/core/kis_transform_visitor.h new file mode 100644 index 00000000..62f6b3e4 --- /dev/null +++ b/krita/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 "qrect.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, + Q_INT32 tx, Q_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; + Q_INT32 m_tx, m_ty; + KisFilterStrategy *m_filter; + double m_angle; + KisProgressDisplayInterface *m_progress; + KisImageSP m_img; +}; + + +#endif diff --git a/krita/core/kis_transform_worker.cc b/krita/core/kis_transform_worker.cc new file mode 100644 index 00000000..bc4dc609 --- /dev/null +++ b/krita/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, + Q_INT32 xtranslate, Q_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; + Q_INT32 pixelSize = src->pixelSize(); + QRect 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 (Q_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; + Q_INT32 pixelSize = src->pixelSize(); + QRect 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 (Q_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; + Q_INT32 pixelSize = src->pixelSize(); + QRect 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 + } + Q_INT32 x = 0; + + for (Q_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; + Q_INT32 pixelSize = src->pixelSize(); + QRect 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 (Q_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, Q_INT32 start, Q_INT32 lineNum, Q_INT32 len); + +template <> KisHLineIteratorPixel createIterator +(KisPaintDevice *dev, Q_INT32 start, Q_INT32 lineNum, Q_INT32 len) +{ + return dev->createHLineIterator(start, lineNum, len, true); +} + +template <> KisVLineIteratorPixel createIterator +(KisPaintDevice *dev, Q_INT32 start, Q_INT32 lineNum, Q_INT32 len) +{ + return dev->createVLineIterator(lineNum, start, len, true); +} + +template void calcDimensions (KisPaintDevice *dev, Q_INT32 &srcStart, Q_INT32 &srcLen, Q_INT32 &firstLine, Q_INT32 &numLines); + +template <> void calcDimensions +(KisPaintDevice *dev, Q_INT32 &srcStart, Q_INT32 &srcLen, Q_INT32 &firstLine, Q_INT32 &numLines) +{ + if(dev->hasSelection()) + { + QRect r = dev->selection()->selectedExactRect(); + r.rect(&srcStart, &firstLine, &srcLen, &numLines); + } + else + dev->exactBounds(srcStart, firstLine, srcLen, numLines); +} + +template <> void calcDimensions +(KisPaintDevice *dev, Q_INT32 &srcStart, Q_INT32 &srcLen, Q_INT32 &firstLine, Q_INT32 &numLines) +{ + if(dev->hasSelection()) + { + QRect r = dev->selection()->selectedExactRect(); + r.rect(&firstLine, &srcStart, &numLines, &srcLen); + } + else + dev->exactBounds(firstLine, srcStart, numLines, srcLen); +} + +struct FilterValues +{ + Q_UINT8 numWeights; + Q_UINT8 *weight; + ~FilterValues() {delete [] weight;} +}; + +template void KisTransformWorker::transformPass(KisPaintDevice *src, KisPaintDevice *dst, double floatscale, double shear, Q_INT32 dx, KisFilterStrategy *filterStrategy, bool fixBorderAlpha) +{ + Q_INT32 lineNum,srcStart,firstLine,srcLen,numLines; + Q_INT32 center, begin, end; /* filter calculation variables */ + Q_UINT8 *data; + Q_UINT8 pixelSize = src->pixelSize(); + KisSelectionSP dstSelection; + KisColorSpace * cs = src->colorSpace(); + Q_INT32 scale; + Q_INT32 scaleDenom; + Q_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; + + Q_INT32 support = filterStrategy->intSupport(); + Q_INT32 dstLen, dstStart; + Q_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 + Q_INT32 extraLen = (support+256)>>8 + 1; + + Q_UINT8 *tmpLine = new Q_UINT8[(srcLen +2*extraLen)* pixelSize]; + Q_CHECK_PTR(tmpLine); + + Q_UINT8 *tmpSel = new Q_UINT8[srcLen+2*extraLen]; + Q_CHECK_PTR(tmpSel); + + //allocate space for colors + const Q_UINT8 **colors = new const Q_UINT8 *[2*support+1]; + + // Precalculate weights + FilterValues *filterWeights = new FilterValues[256]; + + for(int center = 0; center<256; ++center) + { + Q_INT32 begin = (255 + center - support)>>8; // takes ceiling by adding 255 + Q_INT32 span = ((center + support)>>8) - begin + 1; // takes floor to get end. Subtracts begin to get span + Q_INT32 t = (((begin<<8) - center) * invfscale)>>8; + Q_INT32 dt = invfscale; + filterWeights[center].weight = new Q_UINT8[span]; +//printf("%d (",center); + Q_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); + Q_INT32 i = 0; + while(!srcIt.isDone()) + { + Q_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); + Q_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; + QRect 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; + Q_INT32 xtranslate = m_xtranslate; + Q_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->parentLayer()) { + m_dev->parentLayer()->setDirty(); + } + //progress info + emit notifyProgressDone(); + m_dev->emitSelectionChanged(); + + return m_cancelRequested; +} diff --git a/krita/core/kis_transform_worker.h b/krita/core/kis_transform_worker.h new file mode 100644 index 00000000..c357390e --- /dev/null +++ b/krita/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, + Q_INT32 xtranslate, Q_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, Q_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; + Q_INT32 m_xtranslate, m_ytranslate; + KisProgressDisplayInterface *m_progress; + KisFilterStrategy *m_filter; + // Implement KisProgressSubject + bool m_cancelRequested; + virtual void cancel() { m_cancelRequested = true; } + Q_INT32 m_progressTotalSteps; + Q_INT32 m_progressStep; + Q_INT32 m_progressScaler; + Q_INT32 m_lastProgressReport; + bool m_fixBorderAlpha; +}; + + +inline KisTransformWorker::~KisTransformWorker() +{ +} + +#endif // KIS_TRANSFORM_VISITOR_H_ diff --git a/krita/core/kis_types.h b/krita/core/kis_types.h new file mode 100644 index 00000000..94e066fc --- /dev/null +++ b/krita/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 Krita 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 QValueVector vKisSegments; + +//class KisGuide; +//typedef KSharedPtr KisGuideSP; + +class KisAlphaMask; +typedef KSharedPtr KisAlphaMaskSP; + +class KisFilter; +typedef KSharedPtr KisFilterSP; + +#endif // KISTYPES_H_ diff --git a/krita/core/kis_vec.cc b/krita/core/kis_vec.cc new file mode 100644 index 00000000..fa54e1f9 --- /dev/null +++ b/krita/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/krita/core/kis_vec.h b/krita/core/kis_vec.h new file mode 100644 index 00000000..1706dd4e --- /dev/null +++ b/krita/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 QPoint& 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 QPoint& 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/krita/core/tests/Makefile.am b/krita/core/tests/Makefile.am new file mode 100644 index 00000000..de1a869a --- /dev/null +++ b/krita/core/tests/Makefile.am @@ -0,0 +1,30 @@ +AM_CPPFLAGS = \ + -I$(srcdir)/../ \ + -I$(srcdir)/../tiles \ + -I$(srcdir)/../../sdk \ + -I$(srcdir)/../../kritacolor \ + -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 ../../libkritacommon.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 ../../libkritacommon.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 ../../libkritacommon.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/krita/core/tests/kis_filter_configuration_tester.cc b/krita/core/tests/kis_filter_configuration_tester.cc new file mode 100644 index 00000000..10497692 --- /dev/null +++ b/krita/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(), QString("test")); + + delete kfc; + success("testCreation success"); +} + +void KisFilterConfigurationTester::testRoundTrip() +{ + KisFilterConfiguration * kfc = new KisFilterConfiguration("test", 1); + CHECK(kfc->version(), 1); + CHECK(kfc->name(), QString("test")); + QString s = kfc->toString(); + delete kfc; + kfc = new KisFilterConfiguration(s); + CHECK(kfc->version(), 1); + CHECK(kfc->name(), QString("test")); + delete kfc; + success("testDeserializaton success"); +} + +void KisFilterConfigurationTester::testSetGetProperty() +{ +} diff --git a/krita/core/tests/kis_filter_configuration_tester.h b/krita/core/tests/kis_filter_configuration_tester.h new file mode 100644 index 00000000..6e1ca2e5 --- /dev/null +++ b/krita/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/krita/core/tests/kis_image_tester.cpp b/krita/core/tests/kis_image_tester.cpp new file mode 100644 index 00000000..ee180787 --- /dev/null +++ b/krita/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); + + QColor colour; + Q_UINT8 opacity; + + mergedPixel.toQColor(&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, QColor(255, 128, 64), OPACITY_OPAQUE); + + mergedPixel = image->mergedPixel(0, 0); + mergedPixel.toQColor(&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, QColor(255, 255, 255), OPACITY_OPAQUE); + + mergedPixel = image->mergedPixel(0, 0); + mergedPixel.toQColor(&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/krita/core/tests/kis_image_tester.h b/krita/core/tests/kis_image_tester.h new file mode 100644 index 00000000..4e676838 --- /dev/null +++ b/krita/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/krita/core/tests/kis_integer_maths_tester.cpp b/krita/core/tests/kis_integer_maths_tester.cpp new file mode 100644 index 00000000..1878731b --- /dev/null +++ b/krita/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/krita/core/tests/kis_integer_maths_tester.h b/krita/core/tests/kis_integer_maths_tester.h new file mode 100644 index 00000000..2a9a9a20 --- /dev/null +++ b/krita/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/krita/core/tiles/Makefile.am b/krita/core/tiles/Makefile.am new file mode 100644 index 00000000..050cb4a4 --- /dev/null +++ b/krita/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 = libkritatile.la + +libkritatile_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 + +libkritatile_la_METASOURCES = AUTO + +include_HEADERS = \ + kis_tileddatamanager.h +noinst_HEADERS = kis_tiled_random_accessor.h diff --git a/krita/core/tiles/kis_memento.cc b/krita/core/tiles/kis_memento.cc new file mode 100644 index 00000000..ea6ed722 --- /dev/null +++ b/krita/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(Q_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 Q_UINT8[pixelSize]; + m_redoDefPixel = new Q_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(Q_INT32 &x, Q_INT32 &y, Q_INT32 &w, Q_INT32 &h) const +{ + Q_INT32 maxX = Q_INT32_MIN; + Q_INT32 maxY = Q_INT32_MIN; + x = Q_INT32_MAX; + y = Q_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; +} + +QRect KisMemento::extent() const +{ + Q_INT32 x; + Q_INT32 y; + Q_INT32 w; + Q_INT32 h; + + extent(x, y, w, h); + + return QRect(x, y, w, h); +} + +bool KisMemento::containsTile(Q_INT32 col, Q_INT32 row, Q_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/krita/core/tiles/kis_memento.h b/krita/core/tiles/kis_memento.h new file mode 100644 index 00000000..696f8129 --- /dev/null +++ b/krita/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(Q_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(Q_INT32 &x, Q_INT32 &y, Q_INT32 &w, Q_INT32 &h) const; + QRect extent() const; + + bool containsTile(Q_INT32 col, Q_INT32 row, Q_UINT32 tileHash) const; + + // For debugging use + bool valid() const { return m_valid; } + void setInvalid() { m_valid = false; } + +private: + + class DeletedTile { + public: + DeletedTile(Q_INT32 col, Q_INT32 row, const DeletedTile *next) + : m_col(col), + m_row(row), + m_next(next) + { + } + + Q_INT32 col() const { return m_col; } + Q_INT32 row() const { return m_row; } + const DeletedTile *next() const { return m_next; } + + private: + Q_INT32 m_col; + Q_INT32 m_row; + const DeletedTile *m_next; + }; + + class DeletedTileList { + public: + DeletedTileList() + : m_firstDeletedTile(0) + { + } + + ~DeletedTileList(); + + void addTile(Q_INT32 col, Q_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(Q_INT32 col, Q_INT32 row) + { + m_redoDelTilesList.addTile(col, row); + } + + DeletedTile *tileListToDeleteOnRedo() + { + return m_redoDelTilesList.firstTile(); + } + + void clearTilesToDeleteOnRedo() + { + m_redoDelTilesList.clear(); + } + + void addTileToDeleteOnUndo(Q_INT32 col, Q_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; + Q_UINT32 m_numTiles; + KisTile **m_redoHashTable; + DeletedTileList m_redoDelTilesList; + DeletedTileList m_undoDelTilesList; + Q_UINT8 *m_defPixel; + Q_UINT8 *m_redoDefPixel; + void deleteAll(KisTile *tile); + + bool m_valid; +}; + +#endif // KIS_MEMENTO_H_ diff --git a/krita/core/tiles/kis_tile.cc b/krita/core/tiles/kis_tile.cc new file mode 100644 index 00000000..49d20cf6 --- /dev/null +++ b/krita/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 Q_INT32 KisTile::WIDTH = 64; +const Q_INT32 KisTile::HEIGHT = 64; + + +KisTile::KisTile(Q_INT32 pixelSize, Q_INT32 col, Q_INT32 row, const Q_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, Q_INT32 col, Q_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(Q_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(Q_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; +} + +Q_UINT8 *KisTile::data(Q_INT32 x, Q_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 Q_UINT8 *pixel) +{ + addReader(); + Q_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/krita/core/tiles/kis_tile.h b/krita/core/tiles/kis_tile.h new file mode 100644 index 00000000..d80b6e2c --- /dev/null +++ b/krita/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 contains + * a part of a PaintDevice, but only the individual pixels + * are accesable and that only via iterators. + */ +class KisTile { +public: + KisTile(Q_INT32 pixelSize, Q_INT32 col, Q_INT32 row, const Q_UINT8 *defPixel); + KisTile(const KisTile& rhs, Q_INT32 col, Q_INT32 row); + KisTile(const KisTile& rhs); + ~KisTile(); + +public: + void release(); + void allocate(); + + Q_UINT8 *data(Q_INT32 xoff, Q_INT32 yoff) const; + Q_UINT8 *data() const { return m_data; } + + void setData(const Q_UINT8 *pixel); + + Q_INT32 refCount() const; + void ref(); + + Q_INT32 getRow() const { return m_row; } + Q_INT32 getCol() const { return m_col; } + + QRect extent() const { return QRect(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; + Q_INT32 readers() { return m_nReadlock; } + + friend class KisTiledIterator; + friend class KisTiledDataManager; + friend class KisMemento; + friend class KisTileManager; +private: + KisTile& operator=(const KisTile&); + +private: + Q_UINT8 *m_data; + mutable Q_INT32 m_nReadlock; + Q_INT32 m_row; + Q_INT32 m_col; + Q_INT32 m_pixelSize; + KisTile *m_nextTile; + +public: + static const Q_INT32 WIDTH; + static const Q_INT32 HEIGHT; +}; + +#endif // KIS_TILE_H_ + diff --git a/krita/core/tiles/kis_tile_global.h b/krita/core/tiles/kis_tile_global.h new file mode 100644 index 00000000..93052a4f --- /dev/null +++ b/krita/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/krita/core/tiles/kis_tiled_random_accessor.cc b/krita/core/tiles/kis_tiled_random_accessor.cc new file mode 100644 index 00000000..52ec8634 --- /dev/null +++ b/krita/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 Q_UINT32 KisTiledRandomAccessor::CACHESIZE = 4; // Define the number of tiles we keep in cache + +KisTiledRandomAccessor::KisTiledRandomAccessor(KisTiledDataManager *ktm, Q_INT32 x, Q_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(Q_INT32 x, Q_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]; + Q_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++; + } + Q_UINT32 col = xToCol( x ); + Q_UINT32 row = yToRow( y ); + KisTileInfo* kti = fetchTileData(col, row); + Q_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; +} + + +Q_UINT8 * KisTiledRandomAccessor::rawData() const +{ + return m_data; +} + + +const Q_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(Q_INT32 col, Q_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/krita/core/tiles/kis_tiled_random_accessor.h b/krita/core/tiles/kis_tiled_random_accessor.h new file mode 100644 index 00000000..7766f75c --- /dev/null +++ b/krita/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; + Q_UINT8* data; + const Q_UINT8* oldData; + Q_INT32 area_x1, area_y1, area_x2, area_y2; + }; + public: + KisTiledRandomAccessor(KisTiledDataManager *ktm, Q_INT32 x, Q_INT32 y, bool writable); + ~KisTiledRandomAccessor(); + + + private: + inline Q_UINT32 xToCol(Q_UINT32 x) const { if (m_ktm) return m_ktm->xToCol(x); else return 0; }; + inline Q_UINT32 yToRow(Q_UINT32 y) const { if (m_ktm) return m_ktm->yToRow(y); else return 0; }; + KisTileInfo* fetchTileData(Q_INT32 col, Q_INT32 row); + + public: + /// Move to a given x,y position, fetch tiles and data + void moveTo(Q_INT32 x, Q_INT32 y); + Q_UINT8* rawData() const; + const Q_UINT8* oldRawData() const; + + private: + KisTiledDataManager *m_ktm; + KisTileInfo** m_tilesCache; + Q_UINT32 m_tilesCacheSize; + Q_INT32 m_pixelSize; + Q_UINT8* m_data; + const Q_UINT8* m_oldData; + bool m_writable; + static const Q_UINT32 CACHESIZE; // Define the number of tiles we keep in cache + +}; + +#endif diff --git a/krita/core/tiles/kis_tileddatamanager.cc b/krita/core/tiles/kis_tileddatamanager.cc new file mode 100644 index 00000000..4372e487 --- /dev/null +++ b/krita/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(Q_UINT32 pixelSize, const Q_UINT8 *defPixel) +{ + m_pixelSize = pixelSize; + + m_defPixel = new Q_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 = Q_INT32_MAX; + m_extentMinY = Q_INT32_MAX; + m_extentMaxX = Q_INT32_MIN; + m_extentMaxY = Q_INT32_MIN; +} + +KisTiledDataManager::KisTiledDataManager(const KisTiledDataManager & dm) + : KShared() +{ + m_pixelSize = dm.m_pixelSize; + + m_defPixel = new Q_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 Q_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]; + Q_INT32 x,y,w,h; + + QIODevice *stream = store->device(); + if (stream == 0) return false; + //Q_ASSERT(stream != 0); + + stream->readLine(str, 79); + + sscanf(str,"%u",&m_numTiles); + + for(Q_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. + Q_INT32 row = yToRow(y); + Q_INT32 col = xToCol(x); + Q_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(Q_INT32 &x, Q_INT32 &y, Q_INT32 &w, Q_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; + } +} + +QRect KisTiledDataManager::extent() const +{ + Q_INT32 x; + Q_INT32 y; + Q_INT32 w; + Q_INT32 h; + + extent(x, y, w, h); + + return QRect(x, y, w, h); +} + +void KisTiledDataManager::setExtent(Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h) +{ + QRect newRect = QRect(x, y, w, h).normalize(); + //printRect("newRect", newRect); + QRect oldRect = QRect(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.contains(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) + { + QRect tileRect = QRect(tile->getCol() * KisTile::WIDTH, tile->getRow() * KisTile::HEIGHT, KisTile::WIDTH, KisTile::HEIGHT); + //printRect("tileRect", tileRect); + + if (newRect.contains(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 + QRect 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.contains(x,y)) { + Q_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 = Q_INT32_MAX; + m_extentMinY = Q_INT32_MAX; + m_extentMaxX = Q_INT32_MIN; + m_extentMaxY = Q_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(Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h, Q_UINT8 clearValue) +{ + if (w < 1 || h < 1) { + return; + } + + Q_INT32 firstColumn = xToCol(x); + Q_INT32 lastColumn = xToCol(x + w - 1); + + Q_INT32 firstRow = yToRow(y); + Q_INT32 lastRow = yToRow(y + h - 1); + + QRect clearRect(x, y, w, h); + + const Q_UINT32 rowStride = KisTile::WIDTH * m_pixelSize; + + for (Q_INT32 row = firstRow; row <= lastRow; ++row) { + for (Q_INT32 column = firstColumn; column <= lastColumn; ++column) { + + KisTile *tile = getTile(column, row, true); + QRect tileRect = tile->extent(); + + QRect clearTileRect = clearRect & tileRect; + + tile->addReader(); + if (clearTileRect == tileRect) { + // Clear whole tile + memset(tile->data(), clearValue, KisTile::WIDTH * KisTile::HEIGHT * m_pixelSize); + } else { + + Q_UINT32 rowsRemaining = clearTileRect.height(); + Q_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(Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h, const Q_UINT8 *clearPixel) +{ + Q_ASSERT(clearPixel != 0); + + if (clearPixel == 0 || w < 1 || h < 1) { + return; + } + + bool pixelBytesAreTheSame = true; + + for (Q_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 { + + Q_INT32 firstColumn = xToCol(x); + Q_INT32 lastColumn = xToCol(x + w - 1); + + Q_INT32 firstRow = yToRow(y); + Q_INT32 lastRow = yToRow(y + h - 1); + + QRect clearRect(x, y, w, h); + + const Q_UINT32 rowStride = KisTile::WIDTH * m_pixelSize; + + Q_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 Q_UINT8[KisTile::WIDTH * KisTile::HEIGHT * m_pixelSize]; + + Q_UINT8 *dst = clearPixelData; + Q_UINT32 pixelsRemaining = KisTile::WIDTH; + + // Generate one row + while (pixelsRemaining > 0) { + memcpy(dst, clearPixel, m_pixelSize); + dst += m_pixelSize; + --pixelsRemaining; + } + + Q_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 + Q_UINT32 maxRunLength = QMIN(w, KisTile::WIDTH); + + clearPixelData = new Q_UINT8[maxRunLength * m_pixelSize]; + + Q_UINT8 *dst = clearPixelData; + Q_UINT32 pixelsRemaining = maxRunLength; + + while (pixelsRemaining > 0) { + memcpy(dst, clearPixel, m_pixelSize); + dst += m_pixelSize; + --pixelsRemaining; + } + } + + for (Q_INT32 row = firstRow; row <= lastRow; ++row) { + for (Q_INT32 column = firstColumn; column <= lastColumn; ++column) { + + KisTile *tile = getTile(column, row, true); + QRect tileRect = tile->extent(); + + QRect clearTileRect = clearRect & tileRect; + + if (clearTileRect == tileRect) { + + // Clear whole tile + tile->addReader(); + memcpy(tile->data(), clearPixelData, KisTile::WIDTH * KisTile::HEIGHT * m_pixelSize); + tile->removeReader(); + } else { + + Q_UINT32 rowsRemaining = clearTileRect.height(); + tile->addReader(); + Q_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 = Q_INT32_MAX; + m_extentMinY = Q_INT32_MAX; + m_extentMaxX = Q_INT32_MIN; + m_extentMaxY = Q_INT32_MIN; +} + +void KisTiledDataManager::paste(KisDataManagerSP data, Q_INT32 sx, Q_INT32 sy, Q_INT32 dx, Q_INT32 dy, + Q_INT32 w, Q_INT32 h) +{ + //CBR_MISSING + sx=sy=dx=dy=w=h;data=0; +} + + +Q_UINT32 KisTiledDataManager::calcTileHash(Q_INT32 col, Q_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) + { + Q_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(Q_INT32 col, Q_INT32 row, Q_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(Q_INT32 col, Q_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(Q_INT32 col, Q_INT32 row, bool writeAccess) +{ + Q_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(Q_INT32 col, Q_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()); + + Q_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; +} + +Q_UINT8* KisTiledDataManager::pixelPtr(Q_INT32 x, Q_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 QUITE VOLATILE + return pixelPtrSafe(x, y, writable) -> data(); +} + +KisTileDataWrapperSP KisTiledDataManager::pixelPtrSafe(Q_INT32 x, Q_INT32 y, bool writable) { + Q_INT32 row = yToRow(y); + Q_INT32 col = xToCol(x); + + // calc limits within the tile + Q_INT32 yInTile = y - row * KisTile::HEIGHT; + Q_INT32 xInTile = x - col * KisTile::WIDTH; + Q_INT32 offset = m_pixelSize * (yInTile * KisTile::WIDTH + xInTile); + + KisTile *tile = getTile(col, row, writable); + + return new KisTileDataWrapper(tile, offset); +} + +const Q_UINT8* KisTiledDataManager::pixel(Q_INT32 x, Q_INT32 y) +{ + return pixelPtr(x, y, false); +} + +Q_UINT8* KisTiledDataManager::writablePixel(Q_INT32 x, Q_INT32 y) +{ + return pixelPtr(x, y, true); +} + +void KisTiledDataManager::setPixel(Q_INT32 x, Q_INT32 y, const Q_UINT8 * data) +{ + Q_UINT8 *pixel = pixelPtr(x, y, true); + memcpy(pixel, data, m_pixelSize); +} + + +void KisTiledDataManager::readBytes(Q_UINT8 * data, + Q_INT32 x, Q_INT32 y, + Q_INT32 w, Q_INT32 h) +{ + if (data == 0) return; + //Q_ASSERT(data != 0); + if (w < 0) + w = 0; + + if (h < 0) + h = 0; + + Q_INT32 dstY = 0; + Q_INT32 srcY = y; + Q_INT32 rowsRemaining = h; + + while (rowsRemaining > 0) { + + Q_INT32 dstX = 0; + Q_INT32 srcX = x; + Q_INT32 columnsRemaining = w; + Q_INT32 numContiguousSrcRows = numContiguousRows(srcY, srcX, srcX + w - 1); + + Q_INT32 rows = QMIN(numContiguousSrcRows, rowsRemaining); + + while (columnsRemaining > 0) { + + Q_INT32 numContiguousSrcColumns = numContiguousColumns(srcX, srcY, srcY + rows - 1); + + Q_INT32 columns = QMIN(numContiguousSrcColumns, columnsRemaining); + + KisTileDataWrapperSP tileData = pixelPtrSafe(srcX, srcY, false); + const Q_UINT8 *srcData = tileData -> data(); + Q_INT32 srcRowStride = rowStride(srcX, srcY); + + Q_UINT8 *dstData = data + ((dstX + (dstY * w)) * m_pixelSize); + Q_INT32 dstRowStride = w * m_pixelSize; + + for (Q_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 Q_UINT8 * bytes, + Q_INT32 x, Q_INT32 y, + Q_INT32 w, Q_INT32 h) +{ + if (bytes == 0) return; + //Q_ASSERT(bytes != 0); + + // XXX: Is this correct? + if (w < 0) + w = 0; + + if (h < 0) + h = 0; + + Q_INT32 srcY = 0; + Q_INT32 dstY = y; + Q_INT32 rowsRemaining = h; + + while (rowsRemaining > 0) { + + Q_INT32 srcX = 0; + Q_INT32 dstX = x; + Q_INT32 columnsRemaining = w; + Q_INT32 numContiguousdstRows = numContiguousRows(dstY, dstX, dstX + w - 1); + + Q_INT32 rows = QMIN(numContiguousdstRows, rowsRemaining); + + while (columnsRemaining > 0) { + + Q_INT32 numContiguousdstColumns = numContiguousColumns(dstX, dstY, dstY + rows - 1); + + Q_INT32 columns = QMIN(numContiguousdstColumns, columnsRemaining); + + //Q_UINT8 *dstData = writablePixel(dstX, dstY); + KisTileDataWrapperSP tileData = pixelPtrSafe(dstX, dstY, true); + Q_UINT8 *dstData = tileData->data(); + Q_INT32 dstRowStride = rowStride(dstX, dstY); + + const Q_UINT8 *srcData = bytes + ((srcX + (srcY * w)) * m_pixelSize); + Q_INT32 srcRowStride = w * m_pixelSize; + + for (Q_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; + } +} + +Q_INT32 KisTiledDataManager::numContiguousColumns(Q_INT32 x, Q_INT32 minY, Q_INT32 maxY) +{ + Q_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; +} + +Q_INT32 KisTiledDataManager::numContiguousRows(Q_INT32 y, Q_INT32 minX, Q_INT32 maxX) +{ + Q_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; +} + +Q_INT32 KisTiledDataManager::rowStride(Q_INT32 x, Q_INT32 y) +{ + Q_UNUSED(x); + Q_UNUSED(y); + + return KisTile::WIDTH * m_pixelSize; +} + +Q_INT32 KisTiledDataManager::numTiles(void) const +{ + return m_numTiles; +} + +KisTileDataWrapper::KisTileDataWrapper(KisTile* tile, Q_INT32 offset) + : m_tile(tile), m_offset(offset) +{ + m_tile->addReader(); +} + +KisTileDataWrapper::~KisTileDataWrapper() +{ + m_tile->removeReader(); +} diff --git a/krita/core/tiles/kis_tileddatamanager.h b/krita/core/tiles/kis_tileddatamanager.h new file mode 100644 index 00000000..d4976080 --- /dev/null +++ b/krita/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; + Q_INT32 m_offset; +public: + KisTileDataWrapper(KisTile* tile, Q_INT32 offset); + virtual ~KisTileDataWrapper(); + Q_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 Q_UINT8's a single pixel takes. + */ + +class KisTiledDataManager : public KShared { + +protected: + KisTiledDataManager(Q_UINT32 pixelSize, const Q_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 Q_UINT8 *defPixel); + const Q_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: + + Q_UINT32 pixelSize(); + + void extent(Q_INT32 &x, Q_INT32 &y, Q_INT32 &w, Q_INT32 &h) const; + QRect extent() const; + + void setExtent(Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h); + +protected: + + void clear(Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h, Q_UINT8 clearValue); + void clear(Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h, const Q_UINT8 *clearPixel); + void clear(); + + +protected: + + void paste(KisDataManagerSP data, Q_INT32 sx, Q_INT32 sy, Q_INT32 dx, Q_INT32 dy, + Q_INT32 w, Q_INT32 h); + + +protected: + + + /** + * Get a read-only pointer to pixel (x, y). + */ + const Q_UINT8* pixel(Q_INT32 x, Q_INT32 y); + + /** + * Get a read-write pointer to pixel (x, y). + */ + Q_UINT8* writablePixel(Q_INT32 x, Q_INT32 y); + + /** + * write the specified data to x, y. There is no checking on pixelSize! + */ + void setPixel(Q_INT32 x, Q_INT32 y, const Q_UINT8 * data); + + + /** + * Copy the bytes in the specified rect to a vector. The caller is responsible + * for managing the vector. + */ + void readBytes(Q_UINT8 * bytes, + Q_INT32 x, Q_INT32 y, + Q_INT32 w, Q_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 Q_UINT8 * bytes, + Q_INT32 x, Q_INT32 y, + Q_INT32 w, Q_INT32 h); + + /// Get the number of contiguous columns starting at x, valid for all values + /// of y between minY and maxY. + Q_INT32 numContiguousColumns(Q_INT32 x, Q_INT32 minY, Q_INT32 maxY); + + /// Get the number of contiguous rows starting at y, valid for all values + /// of x between minX and maxX. + Q_INT32 numContiguousRows(Q_INT32 y, Q_INT32 minX, Q_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). + Q_INT32 rowStride(Q_INT32 x, Q_INT32 y); + + // For debugging use + Q_INT32 numTiles() const; + +private: + + Q_UINT32 m_pixelSize; + Q_UINT32 m_numTiles; + KisTile *m_defaultTile; + KisTile **m_hashTable; + KisMementoSP m_currentMemento; + Q_INT32 m_extentMinX; + Q_INT32 m_extentMinY; + Q_INT32 m_extentMaxX; + Q_INT32 m_extentMaxY; + Q_UINT8 *m_defPixel; + +private: + + void ensureTileMementoed(Q_INT32 col, Q_INT32 row, Q_UINT32 tileHash, const KisTile *refTile); + KisTile *getOldTile(Q_INT32 col, Q_INT32 row, KisTile *def); + KisTile *getTile(Q_INT32 col, Q_INT32 row, bool writeAccess); + Q_UINT32 calcTileHash(Q_INT32 col, Q_INT32 row); + void updateExtent(Q_INT32 col, Q_INT32 row); + void recalculateExtent(); + void deleteTiles(const KisMemento::DeletedTile *deletedTileList); + Q_INT32 xToCol(Q_INT32 x) const; + Q_INT32 yToRow(Q_INT32 y) const; + void getContiguousColumnsAndRows(Q_INT32 x, Q_INT32 y, Q_INT32 *columns, Q_INT32 *rows); + Q_UINT8* pixelPtr(Q_INT32 x, Q_INT32 y, bool writable); + KisTileDataWrapperSP pixelPtrSafe(Q_INT32 x, Q_INT32 y, bool writable); +}; + + +inline Q_UINT32 KisTiledDataManager::pixelSize() +{ + return m_pixelSize; +} + +inline Q_INT32 KisTiledDataManager::xToCol(Q_INT32 x) const +{ + if (x >= 0) { + return x / KisTile::WIDTH; + } else { + return -(((-x - 1) / KisTile::WIDTH) + 1); + } +} + +inline Q_INT32 KisTiledDataManager::yToRow(Q_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/krita/core/tiles/kis_tiledhlineiterator.cc b/krita/core/tiles/kis_tiledhlineiterator.cc new file mode 100644 index 00000000..37a1195e --- /dev/null +++ b/krita/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, Q_INT32 x, Q_INT32 y, Q_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; + } +} + +Q_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/krita/core/tiles/kis_tilediterator.cc b/krita/core/tiles/kis_tilediterator.cc new file mode 100644 index 00000000..5806a82a --- /dev/null +++ b/krita/core/tiles/kis_tilediterator.cc @@ -0,0 +1,131 @@ +/* + * This file is part of the Krita + * + * 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; +} + +Q_UINT8 * KisTiledIterator::rawData() const +{ + return m_data + m_offset; +} + + +const Q_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(Q_INT32 col, Q_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/krita/core/tiles/kis_tilediterator.h b/krita/core/tiles/kis_tilediterator.h new file mode 100644 index 00000000..02431f4b --- /dev/null +++ b/krita/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; + Q_INT32 m_pixelSize; // bytes per pixel + Q_INT32 m_x; // current x position + Q_INT32 m_y; // cirrent y position + Q_INT32 m_row; // row in tilemgr + Q_INT32 m_col; // col in tilemgr + Q_UINT8 *m_data; + Q_UINT8 *m_oldData; + Q_INT32 m_offset; + KisTile *m_tile; + KisTile* m_oldTile; + bool m_writable; + +protected: + inline Q_UINT32 xToCol(Q_UINT32 x) const { if (m_ktm) return m_ktm->xToCol(x); else return 0; }; + inline Q_UINT32 yToRow(Q_UINT32 y) const { if (m_ktm) return m_ktm->yToRow(y); else return 0; }; + void fetchTileData(Q_INT32 col, Q_INT32 row); + +public: + KisTiledIterator( KisTiledDataManager *ktm); + KisTiledIterator(const KisTiledIterator&); + KisTiledIterator& operator=(const KisTiledIterator&); + ~KisTiledIterator(); + +public: + // current x position + Q_INT32 x() const { return m_x; }; + + // cirrent y position + Q_INT32 y() const { return m_y; }; + + /// Returns a pointer to the pixel data. Do NOT interpret the data - leave that to a colorstrategy + Q_UINT8 *rawData() const; + + /// Returns a pointer to the pixel data as it was at the moment tof he last memento creation. + const Q_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, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h, bool writable); + KisTiledRectIterator(const KisTiledRectIterator&); + KisTiledRectIterator& operator=(const KisTiledRectIterator&); + ~KisTiledRectIterator(); + +public: + Q_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: + Q_INT32 m_left; + Q_INT32 m_top; + Q_INT32 m_w; + Q_INT32 m_h; + Q_INT32 m_topRow; + Q_INT32 m_bottomRow; + Q_INT32 m_leftCol; + Q_INT32 m_rightCol; + Q_INT32 m_xInTile; + Q_INT32 m_yInTile; + Q_INT32 m_leftInTile; + Q_INT32 m_rightInTile; + Q_INT32 m_topInTile; + Q_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, Q_INT32 x, Q_INT32 y, Q_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 + Q_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: + Q_INT32 m_right; + Q_INT32 m_left; + Q_INT32 m_leftCol; + Q_INT32 m_rightCol; + Q_INT32 m_xInTile; + Q_INT32 m_yInTile; + Q_INT32 m_leftInTile; + Q_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, Q_INT32 x, Q_INT32 y, Q_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: + Q_INT32 m_top; + Q_INT32 m_bottom; + Q_INT32 m_topRow; + Q_INT32 m_bottomRow; + Q_INT32 m_xInTile; + Q_INT32 m_yInTile; + Q_INT32 m_topInTile; + Q_INT32 m_bottomInTile; + +private: + void nextTile(); +}; + +#endif // KIS_TILED_ITERATOR_H_ diff --git a/krita/core/tiles/kis_tiledrectiterator.cc b/krita/core/tiles/kis_tiledrectiterator.cc new file mode 100644 index 00000000..73146504 --- /dev/null +++ b/krita/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, Q_INT32 nleft, + Q_INT32 ntop, Q_INT32 nw, Q_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( ) +{ +} + +Q_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/krita/core/tiles/kis_tiledvlineiterator.cc b/krita/core/tiles/kis_tiledvlineiterator.cc new file mode 100644 index 00000000..5b6270e1 --- /dev/null +++ b/krita/core/tiles/kis_tiledvlineiterator.cc @@ -0,0 +1,154 @@ +/* + * This file is part of the Krita + * + * 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, Q_INT32 x, Q_INT32 y, Q_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/krita/core/tiles/kis_tilemanager.cc b/krita/core/tiles/kis_tilemanager.cc new file mode 100644 index 00000000..0ac968fd --- /dev/null +++ b/krita/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 Q_UINT8*[4]; + m_poolPixelSizes = new Q_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 QMutex(true); + m_swapMutex = new QMutex(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.contains(tile)) { + m_swapMutex->unlock(); + return; + } + // Q_ASSERT(m_tileMap.contains(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 (!kritaMmap(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); + QFile* file = info->file->file(); + if(!file) { + kdWarning() << "Opening the file as QFile failed" << endl; + m_swapForbidden = true; + m_swapMutex->unlock(); + return; + } + + int fd = file->handle(); + Q_UINT8* data = 0; + if (!kritaMmap(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 + + Q_UINT32 count = QMIN(m_swappableList.size(), m_swappiness); + + for (Q_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; +} + +Q_UINT8* KisTileManager::requestTileData(Q_INT32 pixelSize) +{ + m_swapMutex->lock(); + + Q_UINT8* data = findTileFor(pixelSize); + if ( data ) { + m_swapMutex->unlock(); + return data; + } + m_swapMutex->unlock(); + return new Q_UINT8[m_tileSize * pixelSize]; +} + +void KisTileManager::dontNeedTileData(Q_UINT8* data, Q_INT32 pixelSize) +{ + m_poolMutex->lock(); + if (isPoolTile(data, pixelSize)) { + reclaimTileToPool(data, pixelSize); + } else + delete[] data; + m_poolMutex->unlock(); +} + +Q_UINT8* KisTileManager::findTileFor(Q_INT32 pixelSize) +{ + m_poolMutex->lock(); + + for (int i = 0; i < 4; i++) { + if (m_poolPixelSizes[i] == pixelSize) { + if (!m_poolFreeList[i].isEmpty()) { + Q_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 Q_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(Q_UINT8* data, Q_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(Q_UINT8* data, Q_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::kritaMmap(Q_UINT8*& result, void *start, size_t length, + int prot, int flags, int fd, off_t offset) { + result = (Q_UINT8*) mmap(start, length, prot, flags, fd, offset); + + // Same here for warning and GUI + if (result == (Q_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 Krita, " + << "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/krita/core/tiles/kis_tilemanager.h b/krita/core/tiles/kis_tilemanager.h new file mode 100644 index 00000000..a66ca634 --- /dev/null +++ b/krita/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 + Q_UINT8* requestTileData(Q_INT32 pixelSize); + void dontNeedTileData(Q_UINT8* data, Q_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; + QValueList::iterator node; + bool inMem; bool onFile; bool mmapped; bool validNode; }; + typedef struct { KTempFile* file; off_t filePos; int size; } FreeInfo; + typedef QMap TileMap; + typedef QValueList TileList; + typedef QValueList FreeList; + typedef QValueVector FreeListList; + typedef QValueList PoolFreeList; + typedef QValueList FileList; + + + TileMap m_tileMap; + TileList m_swappableList; + FreeListList m_freeLists; + FileList m_files; + Q_INT32 m_maxInMem; + Q_INT32 m_currentInMem; + Q_UINT32 m_swappiness; + Q_INT32 m_tileSize; // size of a tile if it used 1 byte per pixel + unsigned long m_bytesInMem; + unsigned long m_bytesTotal; + + Q_UINT8 **m_pools; + Q_INT32 *m_poolPixelSizes; + Q_INT32 m_tilesPerPool; + PoolFreeList *m_poolFreeList; + QMutex * m_poolMutex; + QMutex * 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 apparently 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(); + Q_UINT8* findTileFor(Q_INT32 pixelSize); + bool isPoolTile(Q_UINT8* data, Q_INT32 pixelSize); + void reclaimTileToPool(Q_UINT8* data, Q_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 kritaMmap(Q_UINT8*& result, void *start, size_t length, + int prot, int flags, int fd, off_t offset); +}; + +#endif // KIS_TILEMANAGER_H_ diff --git a/krita/core/tiles/tests/Makefile.am b/krita/core/tiles/tests/Makefile.am new file mode 100644 index 00000000..bc729320 --- /dev/null +++ b/krita/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 ../../../libkritacommon.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/krita/core/tiles/tests/kis_tiled_data_tester.cpp b/krita/core/tiles/tests/kis_tiled_data_tester.cpp new file mode 100644 index 00000000..2d7fbe05 --- /dev/null +++ b/krita/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 Q_UINT8 defaultPixel[TEST_PIXEL_SIZE] = {0, 0, 0, OPACITY_TRANSPARENT}; + +void KisTiledDataTester::allTests() +{ + KisDataManager *dm = new KisDataManager(TEST_PIXEL_SIZE, defaultPixel); + + Q_INT32 extentX; + Q_INT32 extentY; + Q_INT32 extentWidth; + Q_INT32 extentHeight; + + dm->extent(extentX, extentY, extentWidth, extentHeight); + CHECK(extentWidth, 0); + CHECK(extentHeight, 0); + + const Q_UINT8 *readOnlyPixel = dm->pixel(KisTile::WIDTH/2, KisTile::HEIGHT/2); + dm->extent(extentX, extentY, extentWidth, extentHeight); + CHECK(extentWidth, 0); + CHECK(extentHeight, 0); + + Q_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/krita/core/tiles/tests/kis_tiled_data_tester.h b/krita/core/tiles/tests/kis_tiled_data_tester.h new file mode 100644 index 00000000..8a569d23 --- /dev/null +++ b/krita/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/krita/data/Makefile.am b/krita/data/Makefile.am new file mode 100644 index 00000000..da438805 --- /dev/null +++ b/krita/data/Makefile.am @@ -0,0 +1,7 @@ +SUBDIRS = . brushes patterns gradients profiles palettes images +kde_servicetypes_DATA = \ + krita_filter.desktop \ + krita_paintop.desktop \ + krita_plugin.desktop \ + krita_tool.desktop + diff --git a/krita/data/README b/krita/data/README new file mode 100644 index 00000000..7636454d --- /dev/null +++ b/krita/data/README @@ -0,0 +1,13 @@ +Krita 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/krita/data/brushes/10x10square.gbr b/krita/data/brushes/10x10square.gbr new file mode 100644 index 00000000..d680172a Binary files /dev/null and b/krita/data/brushes/10x10square.gbr differ diff --git a/krita/data/brushes/10x10squareBlur.gbr b/krita/data/brushes/10x10squareBlur.gbr new file mode 100644 index 00000000..9c8efe4e Binary files /dev/null and b/krita/data/brushes/10x10squareBlur.gbr differ diff --git a/krita/data/brushes/11circle.gbr b/krita/data/brushes/11circle.gbr new file mode 100644 index 00000000..d843b1b1 Binary files /dev/null and b/krita/data/brushes/11circle.gbr differ diff --git a/krita/data/brushes/11fcircle.gbr b/krita/data/brushes/11fcircle.gbr new file mode 100644 index 00000000..86bd9853 Binary files /dev/null and b/krita/data/brushes/11fcircle.gbr differ diff --git a/krita/data/brushes/13circle.gbr b/krita/data/brushes/13circle.gbr new file mode 100644 index 00000000..ae4269fa Binary files /dev/null and b/krita/data/brushes/13circle.gbr differ diff --git a/krita/data/brushes/13fcircle.gbr b/krita/data/brushes/13fcircle.gbr new file mode 100644 index 00000000..456d1056 Binary files /dev/null and b/krita/data/brushes/13fcircle.gbr differ diff --git a/krita/data/brushes/15circle.gbr b/krita/data/brushes/15circle.gbr new file mode 100644 index 00000000..ce99d36e Binary files /dev/null and b/krita/data/brushes/15circle.gbr differ diff --git a/krita/data/brushes/15fcircle.gbr b/krita/data/brushes/15fcircle.gbr new file mode 100644 index 00000000..c198ef4e Binary files /dev/null and b/krita/data/brushes/15fcircle.gbr differ diff --git a/krita/data/brushes/17circle.gbr b/krita/data/brushes/17circle.gbr new file mode 100644 index 00000000..b063f54c Binary files /dev/null and b/krita/data/brushes/17circle.gbr differ diff --git a/krita/data/brushes/17fcircle.gbr b/krita/data/brushes/17fcircle.gbr new file mode 100644 index 00000000..1a170560 Binary files /dev/null and b/krita/data/brushes/17fcircle.gbr differ diff --git a/krita/data/brushes/19circle.gbr b/krita/data/brushes/19circle.gbr new file mode 100644 index 00000000..a0a581b2 Binary files /dev/null and b/krita/data/brushes/19circle.gbr differ diff --git a/krita/data/brushes/19fcircle.gbr b/krita/data/brushes/19fcircle.gbr new file mode 100644 index 00000000..6418446d Binary files /dev/null and b/krita/data/brushes/19fcircle.gbr differ diff --git a/krita/data/brushes/1circle.gbr b/krita/data/brushes/1circle.gbr new file mode 100644 index 00000000..8c81f6bf Binary files /dev/null and b/krita/data/brushes/1circle.gbr differ diff --git a/krita/data/brushes/20x20square.gbr b/krita/data/brushes/20x20square.gbr new file mode 100644 index 00000000..011259f0 Binary files /dev/null and b/krita/data/brushes/20x20square.gbr differ diff --git a/krita/data/brushes/20x20squareBlur.gbr b/krita/data/brushes/20x20squareBlur.gbr new file mode 100644 index 00000000..fd3df8ed Binary files /dev/null and b/krita/data/brushes/20x20squareBlur.gbr differ diff --git a/krita/data/brushes/3circle.gbr b/krita/data/brushes/3circle.gbr new file mode 100644 index 00000000..ddddec9f Binary files /dev/null and b/krita/data/brushes/3circle.gbr differ diff --git a/krita/data/brushes/3fcircle.gbr b/krita/data/brushes/3fcircle.gbr new file mode 100644 index 00000000..7a07a1af Binary files /dev/null and b/krita/data/brushes/3fcircle.gbr differ diff --git a/krita/data/brushes/5circle.gbr b/krita/data/brushes/5circle.gbr new file mode 100644 index 00000000..c910e294 Binary files /dev/null and b/krita/data/brushes/5circle.gbr differ diff --git a/krita/data/brushes/5fcircle.gbr b/krita/data/brushes/5fcircle.gbr new file mode 100644 index 00000000..83d50423 Binary files /dev/null and b/krita/data/brushes/5fcircle.gbr differ diff --git a/krita/data/brushes/5x5square.gbr b/krita/data/brushes/5x5square.gbr new file mode 100644 index 00000000..921b4531 Binary files /dev/null and b/krita/data/brushes/5x5square.gbr differ diff --git a/krita/data/brushes/5x5squareBlur.gbr b/krita/data/brushes/5x5squareBlur.gbr new file mode 100644 index 00000000..97ae6a03 Binary files /dev/null and b/krita/data/brushes/5x5squareBlur.gbr differ diff --git a/krita/data/brushes/7circle.gbr b/krita/data/brushes/7circle.gbr new file mode 100644 index 00000000..45ea2103 Binary files /dev/null and b/krita/data/brushes/7circle.gbr differ diff --git a/krita/data/brushes/7fcircle.gbr b/krita/data/brushes/7fcircle.gbr new file mode 100644 index 00000000..b069c6f8 Binary files /dev/null and b/krita/data/brushes/7fcircle.gbr differ diff --git a/krita/data/brushes/9circle.gbr b/krita/data/brushes/9circle.gbr new file mode 100644 index 00000000..369d85cc Binary files /dev/null and b/krita/data/brushes/9circle.gbr differ diff --git a/krita/data/brushes/9fcircle.gbr b/krita/data/brushes/9fcircle.gbr new file mode 100644 index 00000000..6e1c414c Binary files /dev/null and b/krita/data/brushes/9fcircle.gbr differ diff --git a/krita/data/brushes/BRUSHES.README b/krita/data/brushes/BRUSHES.README new file mode 100644 index 00000000..c7193aac --- /dev/null +++ b/krita/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/krita/data/brushes/COPYING b/krita/data/brushes/COPYING new file mode 100644 index 00000000..c13faf0d --- /dev/null +++ b/krita/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/krita/data/brushes/DStar11.gbr b/krita/data/brushes/DStar11.gbr new file mode 100644 index 00000000..cab5714a Binary files /dev/null and b/krita/data/brushes/DStar11.gbr differ diff --git a/krita/data/brushes/DStar17.gbr b/krita/data/brushes/DStar17.gbr new file mode 100644 index 00000000..496919cb Binary files /dev/null and b/krita/data/brushes/DStar17.gbr differ diff --git a/krita/data/brushes/DStar25.gbr b/krita/data/brushes/DStar25.gbr new file mode 100644 index 00000000..29f8fb25 Binary files /dev/null and b/krita/data/brushes/DStar25.gbr differ diff --git a/krita/data/brushes/Makefile.am b/krita/data/brushes/Makefile.am new file mode 100644 index 00000000..dea07b4d --- /dev/null +++ b/krita/data/brushes/Makefile.am @@ -0,0 +1,69 @@ +kritabrushesdir = $(prefix)/share/apps/krita/brushes + +kritabrushes_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/krita/data/brushes/SketchBrush-16.gih b/krita/data/brushes/SketchBrush-16.gih new file mode 100644 index 00000000..32c76dec Binary files /dev/null and b/krita/data/brushes/SketchBrush-16.gih differ diff --git a/krita/data/brushes/SketchBrush-32.gih b/krita/data/brushes/SketchBrush-32.gih new file mode 100644 index 00000000..6fae028d Binary files /dev/null and b/krita/data/brushes/SketchBrush-32.gih differ diff --git a/krita/data/brushes/SketchBrush-64.gih b/krita/data/brushes/SketchBrush-64.gih new file mode 100644 index 00000000..8dbff8fd Binary files /dev/null and b/krita/data/brushes/SketchBrush-64.gih differ diff --git a/krita/data/brushes/callig1.gbr b/krita/data/brushes/callig1.gbr new file mode 100644 index 00000000..ef3bfa2b Binary files /dev/null and b/krita/data/brushes/callig1.gbr differ diff --git a/krita/data/brushes/callig2.gbr b/krita/data/brushes/callig2.gbr new file mode 100644 index 00000000..d607dd57 Binary files /dev/null and b/krita/data/brushes/callig2.gbr differ diff --git a/krita/data/brushes/callig3.gbr b/krita/data/brushes/callig3.gbr new file mode 100644 index 00000000..d84c256c Binary files /dev/null and b/krita/data/brushes/callig3.gbr differ diff --git a/krita/data/brushes/callig4.gbr b/krita/data/brushes/callig4.gbr new file mode 100644 index 00000000..8be1bc1d Binary files /dev/null and b/krita/data/brushes/callig4.gbr differ diff --git a/krita/data/brushes/confetti.gbr b/krita/data/brushes/confetti.gbr new file mode 100644 index 00000000..d7ba158e Binary files /dev/null and b/krita/data/brushes/confetti.gbr differ diff --git a/krita/data/brushes/confetti.gih b/krita/data/brushes/confetti.gih new file mode 100644 index 00000000..dfa9cc88 Binary files /dev/null and b/krita/data/brushes/confetti.gih differ diff --git a/krita/data/brushes/cursor.gbr b/krita/data/brushes/cursor.gbr new file mode 100644 index 00000000..80be888e Binary files /dev/null and b/krita/data/brushes/cursor.gbr differ diff --git a/krita/data/brushes/cursor_big_lb.gbr b/krita/data/brushes/cursor_big_lb.gbr new file mode 100644 index 00000000..be0dab11 Binary files /dev/null and b/krita/data/brushes/cursor_big_lb.gbr differ diff --git a/krita/data/brushes/cursor_big_lw.gbr b/krita/data/brushes/cursor_big_lw.gbr new file mode 100644 index 00000000..f9253911 Binary files /dev/null and b/krita/data/brushes/cursor_big_lw.gbr differ diff --git a/krita/data/brushes/cursor_big_rb.gbr b/krita/data/brushes/cursor_big_rb.gbr new file mode 100644 index 00000000..09c356ae Binary files /dev/null and b/krita/data/brushes/cursor_big_rb.gbr differ diff --git a/krita/data/brushes/cursor_big_rw.gbr b/krita/data/brushes/cursor_big_rw.gbr new file mode 100644 index 00000000..53e64f93 Binary files /dev/null and b/krita/data/brushes/cursor_big_rw.gbr differ diff --git a/krita/data/brushes/cursor_lw.gbr b/krita/data/brushes/cursor_lw.gbr new file mode 100644 index 00000000..be41e431 Binary files /dev/null and b/krita/data/brushes/cursor_lw.gbr differ diff --git a/krita/data/brushes/cursor_resize_diag_1.gbr b/krita/data/brushes/cursor_resize_diag_1.gbr new file mode 100644 index 00000000..d3110164 Binary files /dev/null and b/krita/data/brushes/cursor_resize_diag_1.gbr differ diff --git a/krita/data/brushes/cursor_resize_diag_2.gbr b/krita/data/brushes/cursor_resize_diag_2.gbr new file mode 100644 index 00000000..e4be9425 Binary files /dev/null and b/krita/data/brushes/cursor_resize_diag_2.gbr differ diff --git a/krita/data/brushes/cursor_resize_hor.gbr b/krita/data/brushes/cursor_resize_hor.gbr new file mode 100644 index 00000000..fbbbfed8 Binary files /dev/null and b/krita/data/brushes/cursor_resize_hor.gbr differ diff --git a/krita/data/brushes/cursor_resize_vert.gbr b/krita/data/brushes/cursor_resize_vert.gbr new file mode 100644 index 00000000..941eb615 Binary files /dev/null and b/krita/data/brushes/cursor_resize_vert.gbr differ diff --git a/krita/data/brushes/cursor_rw.gbr b/krita/data/brushes/cursor_rw.gbr new file mode 100644 index 00000000..50f2bd1a Binary files /dev/null and b/krita/data/brushes/cursor_rw.gbr differ diff --git a/krita/data/brushes/cursor_small_lb.gbr b/krita/data/brushes/cursor_small_lb.gbr new file mode 100644 index 00000000..b64e1371 Binary files /dev/null and b/krita/data/brushes/cursor_small_lb.gbr differ diff --git a/krita/data/brushes/cursor_small_lw.gbr b/krita/data/brushes/cursor_small_lw.gbr new file mode 100644 index 00000000..abdcaacd Binary files /dev/null and b/krita/data/brushes/cursor_small_lw.gbr differ diff --git a/krita/data/brushes/cursor_small_rb.gbr b/krita/data/brushes/cursor_small_rb.gbr new file mode 100644 index 00000000..90058590 Binary files /dev/null and b/krita/data/brushes/cursor_small_rb.gbr differ diff --git a/krita/data/brushes/cursor_small_rw.gbr b/krita/data/brushes/cursor_small_rw.gbr new file mode 100644 index 00000000..5b928fbe Binary files /dev/null and b/krita/data/brushes/cursor_small_rw.gbr differ diff --git a/krita/data/brushes/cursor_tiny_lw.gbr b/krita/data/brushes/cursor_tiny_lw.gbr new file mode 100644 index 00000000..d2b67eb9 Binary files /dev/null and b/krita/data/brushes/cursor_tiny_lw.gbr differ diff --git a/krita/data/brushes/cursor_tiny_rw.gbr b/krita/data/brushes/cursor_tiny_rw.gbr new file mode 100644 index 00000000..a8293bf8 Binary files /dev/null and b/krita/data/brushes/cursor_tiny_rw.gbr differ diff --git a/krita/data/brushes/cursor_up.gbr b/krita/data/brushes/cursor_up.gbr new file mode 100644 index 00000000..edb8ebec Binary files /dev/null and b/krita/data/brushes/cursor_up.gbr differ diff --git a/krita/data/brushes/dunes.gbr b/krita/data/brushes/dunes.gbr new file mode 100644 index 00000000..fc7eed23 Binary files /dev/null and b/krita/data/brushes/dunes.gbr differ diff --git a/krita/data/brushes/feltpen.gih b/krita/data/brushes/feltpen.gih new file mode 100644 index 00000000..37d9c771 Binary files /dev/null and b/krita/data/brushes/feltpen.gih differ diff --git a/krita/data/brushes/galaxy.gbr b/krita/data/brushes/galaxy.gbr new file mode 100644 index 00000000..20a13c26 Binary files /dev/null and b/krita/data/brushes/galaxy.gbr differ diff --git a/krita/data/brushes/galaxy_big.gbr b/krita/data/brushes/galaxy_big.gbr new file mode 100644 index 00000000..dbcc5689 Binary files /dev/null and b/krita/data/brushes/galaxy_big.gbr differ diff --git a/krita/data/brushes/galaxy_small.gbr b/krita/data/brushes/galaxy_small.gbr new file mode 100644 index 00000000..d7f3da57 Binary files /dev/null and b/krita/data/brushes/galaxy_small.gbr differ diff --git a/krita/data/brushes/hsparks.gih b/krita/data/brushes/hsparks.gih new file mode 100644 index 00000000..99f75cd9 Binary files /dev/null and b/krita/data/brushes/hsparks.gih differ diff --git a/krita/data/brushes/pepper.gbr b/krita/data/brushes/pepper.gbr new file mode 100644 index 00000000..34861d14 Binary files /dev/null and b/krita/data/brushes/pepper.gbr differ diff --git a/krita/data/brushes/pixel.gbr b/krita/data/brushes/pixel.gbr new file mode 100644 index 00000000..9de22c12 Binary files /dev/null and b/krita/data/brushes/pixel.gbr differ diff --git a/krita/data/brushes/vine.gih b/krita/data/brushes/vine.gih new file mode 100644 index 00000000..65acae04 Binary files /dev/null and b/krita/data/brushes/vine.gih differ diff --git a/krita/data/gradients/Abstract_1.ggr b/krita/data/gradients/Abstract_1.ggr new file mode 100644 index 00000000..5e681d22 --- /dev/null +++ b/krita/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/krita/data/gradients/Abstract_2.ggr b/krita/data/gradients/Abstract_2.ggr new file mode 100644 index 00000000..913ae019 --- /dev/null +++ b/krita/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/krita/data/gradients/Abstract_3.ggr b/krita/data/gradients/Abstract_3.ggr new file mode 100644 index 00000000..5052750a --- /dev/null +++ b/krita/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/krita/data/gradients/Aneurism.ggr b/krita/data/gradients/Aneurism.ggr new file mode 100644 index 00000000..092b2292 --- /dev/null +++ b/krita/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/krita/data/gradients/Blinds.ggr b/krita/data/gradients/Blinds.ggr new file mode 100644 index 00000000..a6bca825 --- /dev/null +++ b/krita/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/krita/data/gradients/Blue_Green.ggr b/krita/data/gradients/Blue_Green.ggr new file mode 100644 index 00000000..4b504576 --- /dev/null +++ b/krita/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/krita/data/gradients/Browns.ggr b/krita/data/gradients/Browns.ggr new file mode 100644 index 00000000..7b826a39 --- /dev/null +++ b/krita/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/krita/data/gradients/Brushed_Aluminium.ggr b/krita/data/gradients/Brushed_Aluminium.ggr new file mode 100644 index 00000000..3b246258 --- /dev/null +++ b/krita/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/krita/data/gradients/Burning_Paper.ggr b/krita/data/gradients/Burning_Paper.ggr new file mode 100644 index 00000000..df064eb0 --- /dev/null +++ b/krita/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/krita/data/gradients/Burning_Transparency.ggr b/krita/data/gradients/Burning_Transparency.ggr new file mode 100644 index 00000000..fccbc4a9 --- /dev/null +++ b/krita/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/krita/data/gradients/CD.ggr b/krita/data/gradients/CD.ggr new file mode 100644 index 00000000..824df960 --- /dev/null +++ b/krita/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/krita/data/gradients/CD_Half.ggr b/krita/data/gradients/CD_Half.ggr new file mode 100644 index 00000000..fdc5dd38 --- /dev/null +++ b/krita/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/krita/data/gradients/Caribbean_Blues.ggr b/krita/data/gradients/Caribbean_Blues.ggr new file mode 100644 index 00000000..232b7b8b --- /dev/null +++ b/krita/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/krita/data/gradients/Coffee.ggr b/krita/data/gradients/Coffee.ggr new file mode 100644 index 00000000..24baee0e --- /dev/null +++ b/krita/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/krita/data/gradients/Cold_Steel.ggr b/krita/data/gradients/Cold_Steel.ggr new file mode 100644 index 00000000..f6b27a02 --- /dev/null +++ b/krita/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/krita/data/gradients/Cold_Steel_2.ggr b/krita/data/gradients/Cold_Steel_2.ggr new file mode 100644 index 00000000..f09dcf89 --- /dev/null +++ b/krita/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/krita/data/gradients/Crown_molding.ggr b/krita/data/gradients/Crown_molding.ggr new file mode 100644 index 00000000..56ffb013 --- /dev/null +++ b/krita/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/krita/data/gradients/Dark_1.ggr b/krita/data/gradients/Dark_1.ggr new file mode 100644 index 00000000..52a0f804 --- /dev/null +++ b/krita/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/krita/data/gradients/Deep_Sea.ggr b/krita/data/gradients/Deep_Sea.ggr new file mode 100644 index 00000000..c6cfc5fe --- /dev/null +++ b/krita/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/krita/data/gradients/Default.ggr b/krita/data/gradients/Default.ggr new file mode 100644 index 00000000..82511f35 --- /dev/null +++ b/krita/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/krita/data/gradients/Flare_Glow_Angular_1.ggr b/krita/data/gradients/Flare_Glow_Angular_1.ggr new file mode 100644 index 00000000..b0e2dc9c --- /dev/null +++ b/krita/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/krita/data/gradients/Flare_Glow_Radial_1.ggr b/krita/data/gradients/Flare_Glow_Radial_1.ggr new file mode 100644 index 00000000..318f43fe --- /dev/null +++ b/krita/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/krita/data/gradients/Flare_Glow_Radial_2.ggr b/krita/data/gradients/Flare_Glow_Radial_2.ggr new file mode 100644 index 00000000..97282599 --- /dev/null +++ b/krita/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/krita/data/gradients/Flare_Glow_Radial_3.ggr b/krita/data/gradients/Flare_Glow_Radial_3.ggr new file mode 100644 index 00000000..42c24e1a --- /dev/null +++ b/krita/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/krita/data/gradients/Flare_Glow_Radial_4.ggr b/krita/data/gradients/Flare_Glow_Radial_4.ggr new file mode 100644 index 00000000..966f8538 --- /dev/null +++ b/krita/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/krita/data/gradients/Flare_Radial_101.ggr b/krita/data/gradients/Flare_Radial_101.ggr new file mode 100644 index 00000000..eff7920f --- /dev/null +++ b/krita/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/krita/data/gradients/Flare_Radial_102.ggr b/krita/data/gradients/Flare_Radial_102.ggr new file mode 100644 index 00000000..ac50a3c9 --- /dev/null +++ b/krita/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/krita/data/gradients/Flare_Radial_103.ggr b/krita/data/gradients/Flare_Radial_103.ggr new file mode 100644 index 00000000..a73fbe9e --- /dev/null +++ b/krita/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/krita/data/gradients/Flare_Rays_Radial_1.ggr b/krita/data/gradients/Flare_Rays_Radial_1.ggr new file mode 100644 index 00000000..66a848d5 --- /dev/null +++ b/krita/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/krita/data/gradients/Flare_Rays_Radial_2.ggr b/krita/data/gradients/Flare_Rays_Radial_2.ggr new file mode 100644 index 00000000..c38e061c --- /dev/null +++ b/krita/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/krita/data/gradients/Flare_Rays_Size_1.ggr b/krita/data/gradients/Flare_Rays_Size_1.ggr new file mode 100644 index 00000000..f5d85e7f --- /dev/null +++ b/krita/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/krita/data/gradients/Flare_Sizefac_101.ggr b/krita/data/gradients/Flare_Sizefac_101.ggr new file mode 100644 index 00000000..e654a9ee --- /dev/null +++ b/krita/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/krita/data/gradients/Four_bars.ggr b/krita/data/gradients/Four_bars.ggr new file mode 100644 index 00000000..7a0a3e24 --- /dev/null +++ b/krita/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/krita/data/gradients/French_flag.ggr b/krita/data/gradients/French_flag.ggr new file mode 100644 index 00000000..a6167970 --- /dev/null +++ b/krita/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/krita/data/gradients/French_flag_smooth.ggr b/krita/data/gradients/French_flag_smooth.ggr new file mode 100644 index 00000000..61b179df --- /dev/null +++ b/krita/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/krita/data/gradients/Full_saturation_spectrum_CCW.ggr b/krita/data/gradients/Full_saturation_spectrum_CCW.ggr new file mode 100644 index 00000000..9bd2ea3b --- /dev/null +++ b/krita/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/krita/data/gradients/Full_saturation_spectrum_CW.ggr b/krita/data/gradients/Full_saturation_spectrum_CW.ggr new file mode 100644 index 00000000..d70ba643 --- /dev/null +++ b/krita/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/krita/data/gradients/German_flag.ggr b/krita/data/gradients/German_flag.ggr new file mode 100644 index 00000000..8d76ac20 --- /dev/null +++ b/krita/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/krita/data/gradients/German_flag_smooth.ggr b/krita/data/gradients/German_flag_smooth.ggr new file mode 100644 index 00000000..efadfdbc --- /dev/null +++ b/krita/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/krita/data/gradients/Golden.ggr b/krita/data/gradients/Golden.ggr new file mode 100644 index 00000000..4f1a65e2 --- /dev/null +++ b/krita/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/krita/data/gradients/Greens.ggr b/krita/data/gradients/Greens.ggr new file mode 100644 index 00000000..0f307a01 --- /dev/null +++ b/krita/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/krita/data/gradients/Horizon_1.ggr b/krita/data/gradients/Horizon_1.ggr new file mode 100644 index 00000000..25db002b --- /dev/null +++ b/krita/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/krita/data/gradients/Horizon_2.ggr b/krita/data/gradients/Horizon_2.ggr new file mode 100644 index 00000000..e2d07424 --- /dev/null +++ b/krita/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/krita/data/gradients/Incandescent.ggr b/krita/data/gradients/Incandescent.ggr new file mode 100644 index 00000000..64a3438b --- /dev/null +++ b/krita/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/krita/data/gradients/Land_1.ggr b/krita/data/gradients/Land_1.ggr new file mode 100644 index 00000000..a2180779 --- /dev/null +++ b/krita/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/krita/data/gradients/Land_and_Sea.ggr b/krita/data/gradients/Land_and_Sea.ggr new file mode 100644 index 00000000..a932b188 --- /dev/null +++ b/krita/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/krita/data/gradients/Makefile.am b/krita/data/gradients/Makefile.am new file mode 100644 index 00000000..46df0213 --- /dev/null +++ b/krita/data/gradients/Makefile.am @@ -0,0 +1,4 @@ + +kritagradientsdir = $(prefix)/share/apps/krita/gradients + +kritagradients_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/krita/data/gradients/Metallic_Something.ggr b/krita/data/gradients/Metallic_Something.ggr new file mode 100644 index 00000000..19e675b7 --- /dev/null +++ b/krita/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/krita/data/gradients/Mexican_flag.ggr b/krita/data/gradients/Mexican_flag.ggr new file mode 100644 index 00000000..bcb7686d --- /dev/null +++ b/krita/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/krita/data/gradients/Mexican_flag_smooth.ggr b/krita/data/gradients/Mexican_flag_smooth.ggr new file mode 100644 index 00000000..ee363116 --- /dev/null +++ b/krita/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/krita/data/gradients/Nauseating_Headache.ggr b/krita/data/gradients/Nauseating_Headache.ggr new file mode 100644 index 00000000..347453ac --- /dev/null +++ b/krita/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/krita/data/gradients/Neon_Cyan.ggr b/krita/data/gradients/Neon_Cyan.ggr new file mode 100644 index 00000000..4ae27583 --- /dev/null +++ b/krita/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/krita/data/gradients/Neon_Green.ggr b/krita/data/gradients/Neon_Green.ggr new file mode 100644 index 00000000..1f7402f8 --- /dev/null +++ b/krita/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/krita/data/gradients/Neon_Yellow.ggr b/krita/data/gradients/Neon_Yellow.ggr new file mode 100644 index 00000000..31648b04 --- /dev/null +++ b/krita/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/krita/data/gradients/Pastel_Rainbow.ggr b/krita/data/gradients/Pastel_Rainbow.ggr new file mode 100644 index 00000000..28a71847 --- /dev/null +++ b/krita/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/krita/data/gradients/Pastels.ggr b/krita/data/gradients/Pastels.ggr new file mode 100644 index 00000000..f57fa5af --- /dev/null +++ b/krita/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/krita/data/gradients/Purples.ggr b/krita/data/gradients/Purples.ggr new file mode 100644 index 00000000..6c6ce689 --- /dev/null +++ b/krita/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/krita/data/gradients/Radial_Eyeball_Blue.ggr b/krita/data/gradients/Radial_Eyeball_Blue.ggr new file mode 100644 index 00000000..9a23068b --- /dev/null +++ b/krita/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/krita/data/gradients/Radial_Eyeball_Brown.ggr b/krita/data/gradients/Radial_Eyeball_Brown.ggr new file mode 100644 index 00000000..c9049440 --- /dev/null +++ b/krita/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/krita/data/gradients/Radial_Eyeball_Green.ggr b/krita/data/gradients/Radial_Eyeball_Green.ggr new file mode 100644 index 00000000..5352ec6f --- /dev/null +++ b/krita/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/krita/data/gradients/Radial_Glow_1.ggr b/krita/data/gradients/Radial_Glow_1.ggr new file mode 100644 index 00000000..7169c67b --- /dev/null +++ b/krita/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/krita/data/gradients/Radial_Rainbow_Hoop.ggr b/krita/data/gradients/Radial_Rainbow_Hoop.ggr new file mode 100644 index 00000000..b34ad915 --- /dev/null +++ b/krita/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/krita/data/gradients/Romanian_flag.ggr b/krita/data/gradients/Romanian_flag.ggr new file mode 100644 index 00000000..bcdb9bca --- /dev/null +++ b/krita/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/krita/data/gradients/Romanian_flag_smooth.ggr b/krita/data/gradients/Romanian_flag_smooth.ggr new file mode 100644 index 00000000..08a3daeb --- /dev/null +++ b/krita/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/krita/data/gradients/Rounded_edge.ggr b/krita/data/gradients/Rounded_edge.ggr new file mode 100644 index 00000000..5cb2f6c6 --- /dev/null +++ b/krita/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/krita/data/gradients/Shadows_1.ggr b/krita/data/gradients/Shadows_1.ggr new file mode 100644 index 00000000..14574edc --- /dev/null +++ b/krita/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/krita/data/gradients/Shadows_2.ggr b/krita/data/gradients/Shadows_2.ggr new file mode 100644 index 00000000..31b4f7f2 --- /dev/null +++ b/krita/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/krita/data/gradients/Shadows_3.ggr b/krita/data/gradients/Shadows_3.ggr new file mode 100644 index 00000000..eb9366d8 --- /dev/null +++ b/krita/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/krita/data/gradients/Skyline.ggr b/krita/data/gradients/Skyline.ggr new file mode 100644 index 00000000..ba43e817 --- /dev/null +++ b/krita/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/krita/data/gradients/Skyline_polluted.ggr b/krita/data/gradients/Skyline_polluted.ggr new file mode 100644 index 00000000..5677742a --- /dev/null +++ b/krita/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/krita/data/gradients/Square_Wood_Frame.ggr b/krita/data/gradients/Square_Wood_Frame.ggr new file mode 100644 index 00000000..3314e7b2 --- /dev/null +++ b/krita/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/krita/data/gradients/Sunrise.ggr b/krita/data/gradients/Sunrise.ggr new file mode 100644 index 00000000..2bb3beff --- /dev/null +++ b/krita/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/krita/data/gradients/Three_bars_sin.ggr b/krita/data/gradients/Three_bars_sin.ggr new file mode 100644 index 00000000..564d15c7 --- /dev/null +++ b/krita/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/krita/data/gradients/Tropical_Colors.ggr b/krita/data/gradients/Tropical_Colors.ggr new file mode 100644 index 00000000..bbb0fdac --- /dev/null +++ b/krita/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/krita/data/gradients/Tube_Red.ggr b/krita/data/gradients/Tube_Red.ggr new file mode 100644 index 00000000..379fe1cc --- /dev/null +++ b/krita/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/krita/data/gradients/Wood_1.ggr b/krita/data/gradients/Wood_1.ggr new file mode 100644 index 00000000..15fcd106 --- /dev/null +++ b/krita/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/krita/data/gradients/Wood_2.ggr b/krita/data/gradients/Wood_2.ggr new file mode 100644 index 00000000..b23ea06a --- /dev/null +++ b/krita/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/krita/data/gradients/Yellow_Contrast.ggr b/krita/data/gradients/Yellow_Contrast.ggr new file mode 100644 index 00000000..dd3d89fb --- /dev/null +++ b/krita/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/krita/data/gradients/Yellow_Orange.ggr b/krita/data/gradients/Yellow_Orange.ggr new file mode 100644 index 00000000..ac1fe233 --- /dev/null +++ b/krita/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/krita/data/images/Azay-Le-Rideau.jpg b/krita/data/images/Azay-Le-Rideau.jpg new file mode 100644 index 00000000..eb189459 Binary files /dev/null and b/krita/data/images/Azay-Le-Rideau.jpg differ diff --git a/krita/data/images/Makefile.am b/krita/data/images/Makefile.am new file mode 100644 index 00000000..883581ab --- /dev/null +++ b/krita/data/images/Makefile.am @@ -0,0 +1,6 @@ + +kritaimagesdir = $(prefix)/share/apps/krita/images + +# kritaimages_DATA = evenings.jpg hakonepa.jpg hiro_awate.jpg Azay-Le-Rideau.jpg previewfilter.png +kritaimages_DATA = previewfilter.png + diff --git a/krita/data/images/WeyDesc.png b/krita/data/images/WeyDesc.png new file mode 100644 index 00000000..377bf69c Binary files /dev/null and b/krita/data/images/WeyDesc.png differ diff --git a/krita/data/images/evenings.jpg b/krita/data/images/evenings.jpg new file mode 100644 index 00000000..7a61f9a4 Binary files /dev/null and b/krita/data/images/evenings.jpg differ diff --git a/krita/data/images/hakonepa.jpg b/krita/data/images/hakonepa.jpg new file mode 100644 index 00000000..bd998ab7 Binary files /dev/null and b/krita/data/images/hakonepa.jpg differ diff --git a/krita/data/images/hiro_awate.jpg b/krita/data/images/hiro_awate.jpg new file mode 100644 index 00000000..d3fb812d Binary files /dev/null and b/krita/data/images/hiro_awate.jpg differ diff --git a/krita/data/images/paintbrush.png b/krita/data/images/paintbrush.png new file mode 100644 index 00000000..6a4ce818 Binary files /dev/null and b/krita/data/images/paintbrush.png differ diff --git a/krita/data/images/previewfilter.png b/krita/data/images/previewfilter.png new file mode 100644 index 00000000..d68f8fd7 Binary files /dev/null and b/krita/data/images/previewfilter.png differ diff --git a/krita/data/krita_filter.desktop b/krita/data/krita_filter.desktop new file mode 100644 index 00000000..a00ea831 --- /dev/null +++ b/krita/data/krita_filter.desktop @@ -0,0 +1,47 @@ +[Desktop Entry] +Type=ServiceType +X-KDE-ServiceType=Krita/Filter +Comment=Filter plugin for Krita +Comment[bg]=Приставка за филтриране за Krita +Comment[ca]=Connector de filtre per a Krita +Comment[da]=Plugin med filter for Krita +Comment[de]=Filter-Modul für Krita +Comment[el]=Πρόσθετο φίλτρου για το Krita +Comment[eo]=Filtrilkromaĵo por Krita +Comment[es]=Complemento de filtrado para Krita +Comment[et]=Krita filtriplugin +Comment[eu]=Krita-ren iragazkia +Comment[fa]=وصلۀ پالایه برای Krita +Comment[fi]=Suodinliitännäinen Kritalle +Comment[fr]=Module de filtres de Krita +Comment[fy]=Filterplugin foar Krita +Comment[gl]=Plugin de filtro para Krita +Comment[he]=תוסף סינון של Krita +Comment[hu]=Szűrőmodul a Kritához +Comment[is]=Síu íforrit fyrir Krita +Comment[it]=Plugin di filtro per Krita +Comment[ja]=Krita フィルタプラグイン +Comment[km]=កម្មវិធី​ជំនួយ​តម្រង​សម្រាប់ Krita +Comment[lv]=Krita filtra spraudnis +Comment[ms]=Plugin penapis Krita +Comment[nb]=Filter-programtillegg for Krita +Comment[nds]=Filtermoduul för Krita +Comment[ne]=क्रिताका लागि फिल्टर प्लगइन +Comment[nl]=Filterplugin voor Krita +Comment[nn]=Krita-programtillegg for filter +Comment[pl]=Wtyczka filtrów dla Krita +Comment[pt]='Plugin' de filtragem do Krita +Comment[pt_BR]=Plugin de filtro para o Krita +Comment[ru]=Фильтр Krita +Comment[sk]=Filter modul pre Krita +Comment[sl]=Vstavek za filtriranje za Krito +Comment[sr]=Филтерски прикључак за Krita-у +Comment[sr@Latn]=Filterski priključak za Krita-u +Comment[sv]=Insticksprogram med filter för Krita +Comment[uk]=Втулок фільтра для Krita +Comment[uz]=Krita uchun filter plagini +Comment[uz@cyrillic]=Krita учун филтер плагини +Comment[zh_CN]=Krita 过滤器插件 +Comment[zh_TW]=Krita 的過濾器外掛程式 +[PropertyDef::X-Krita-Version] +Type=int diff --git a/krita/data/krita_paintop.desktop b/krita/data/krita_paintop.desktop new file mode 100644 index 00000000..9534b85f --- /dev/null +++ b/krita/data/krita_paintop.desktop @@ -0,0 +1,41 @@ +[Desktop Entry] +Type=ServiceType +X-KDE-ServiceType=Krita/Paintop +Comment=Paint operation plugin for Krita +Comment[bg]=Приставка за рисуване за Krita +Comment[ca]=Connector d'operació de pintura per a Krita +Comment[da]=Plugin med malehandlinger for Krita +Comment[de]=Maloperation-Modul für Krita +Comment[el]=Πρόσθετο λειτουργίας ζωγραφικής για το Krita +Comment[eo]=Pentrooperacia kromaĵo por Krita +Comment[es]=Complemento de operación de pintura para Krita +Comment[et]=Krita joonistamistoimingute plugin +Comment[fa]=وصلۀ عمل رنگ‌آمیزی برای Krita +Comment[fi]=Kritan maalaustoimintoliitännäinen +Comment[fr]=Module d'opération pour Krita +Comment[fy]=Ferfhannelingsplugin foar Krita +Comment[gl]=Plugin de pintar para Krita +Comment[he]=תוסף פעולת צביעה של Krita +Comment[hu]=Festőmodul a Kritához +Comment[is]=Málunar íforrit fyrir Krita +Comment[it]=Plugin per l'operazione di disegno per Krita +Comment[ja]=Krita 描画操作プラグイン +Comment[km]=កម្មវិធី​ជំនួយ​ក្នុង​ការ​គូរ សម្រាប់ Krita +Comment[nb]=Krita-programtillegg for male-handlinger +Comment[nds]=Maalmoduul för Krita +Comment[ne]=क्रिताका लागि पेन्ट अपरेसन प्लगइन +Comment[nl]=Verfverrichtingplugin voor Krita +Comment[pl]=Wtyczka operacji malowania dla Krita +Comment[pt]='Plugin' de operações de pintura do Krita +Comment[pt_BR]=Plugin de operações de pintura do Krita +Comment[ru]=Инструмент рисования Krita +Comment[sk]=Kresliaci modul pre Krita +Comment[sl]=Vstavek s slikarskim postopkom za Krito +Comment[sr]=Прикључак за сликарске операције за Krita-у +Comment[sr@Latn]=Priključak za slikarske operacije za Krita-u +Comment[sv]=Insticksprogram med målningsåtgärder för Krita +Comment[uk]=Втулок малювання для Krita +Comment[zh_CN]=Krita 的绘画操作插件 +Comment[zh_TW]=Krita 的繪畫操作外掛程式 +[PropertyDef::X-Krita-Version] +Type=int diff --git a/krita/data/krita_plugin.desktop b/krita/data/krita_plugin.desktop new file mode 100644 index 00000000..3c2d862c --- /dev/null +++ b/krita/data/krita_plugin.desktop @@ -0,0 +1,42 @@ +[Desktop Entry] +Type=ServiceType +X-KDE-ServiceType=Krita/ViewPlugin +Comment=GUI functionality for Krita +Comment[bg]=ГПИ функционалност за Krita +Comment[ca]=Funcionalitat d'interfície d'usuari per a Krita +Comment[cy]=Swyddogaeth GUI ar gyfer Krita +Comment[da]=GUI-funktionalitet for Krita +Comment[de]=GUI-Funktionalität für Krita +Comment[el]=Άρθρωμα λειτουργικότητας περιβάλλοντος για το Krita +Comment[es]=Funcionalidad de GUI para Krita +Comment[et]=Krita GUI funktsioonid +Comment[fa]=کارآمدی ونک برای Krita +Comment[fr]=Interface graphique pour Krita +Comment[fy]=Ynterfacefunksjonaliteit foar Krita +Comment[gl]=Funcionalidade da GUI de Krita +Comment[he]=מודול פונקציונליות בסיסית של Krita +Comment[hu]=Grafikus felület a Kritához +Comment[is]=Gluggavirkni fyrir Krita +Comment[it]=Funzionalità d'interfaccia per Krita +Comment[ja]=Krita の GUI 機能 +Comment[km]=មុខងារ​ចំណុចប្រទាក់​អ្នក​ប្រើ សម្រាប់ Krita +Comment[nb]=Krita-modul for GUI-funksjonalitet +Comment[nds]=Böversietfunkschonen för Krita +Comment[ne]=क्रिताका लागि GUI कार्यात्मक +Comment[nl]=Interfacefunctionaliteit voor Krita +Comment[pl]=Graficzny interfejs użytkownika programu Krita +Comment[pt]=Funcionalidade gráfica para o Krita +Comment[pt_BR]=Funcionalidade de interface gráfica para o Krita +Comment[ru]=Интерфейс Krita +Comment[sk]=GUI functionalita pre Krita +Comment[sl]=Funkcionalnost grafičnega vmesnika za Krito +Comment[sr]=Функционалност GUI-ја за Krita-у +Comment[sr@Latn]=Funkcionalnost GUI-ja za Krita-u +Comment[sv]=Grafisk gränssnittsfunktion för Krita +Comment[uk]=Функціональність графічного інтерфейсу для Krita +Comment[uz]=Krita grafik interfeysi +Comment[uz@cyrillic]=Krita график интерфейси +Comment[zh_CN]=Krita 的图形界面模块 +Comment[zh_TW]=Krita 的 GUI 功能 +[PropertyDef::X-Krita-Version] +Type=int diff --git a/krita/data/krita_tool.desktop b/krita/data/krita_tool.desktop new file mode 100644 index 00000000..4a1d0d73 --- /dev/null +++ b/krita/data/krita_tool.desktop @@ -0,0 +1,46 @@ +[Desktop Entry] +Type=ServiceType +X-KDE-ServiceType=Krita/Tool +Comment=Tool plugin for Krita +Comment[bg]=Приставка за инструмент за Krita +Comment[ca]=Connector d'eines per a Krita +Comment[da]=Værktøjsplugin for Krita +Comment[de]=Werkzeug-Modul für Krita +Comment[el]=Πρόσθετο εργαλείων για το Krita +Comment[eo]=Ilkromaĵo por Krita +Comment[es]=Complemento de herramienta para Krita +Comment[et]=Krita tööriistade plugin +Comment[eu]=Krita-ren Tresna plugina +Comment[fa]=وصله ابزار برای Krita +Comment[fi]=Kritan työkaluliitännäinen +Comment[fr]=Module d'outils pour Krita +Comment[fy]=Arkplugin foar Krita +Comment[gl]=Ferramenta de plugin para Krita +Comment[he]=תוסף כלים של Krita +Comment[hu]=Eszközmodul a Kritához +Comment[is]=Tóla íforrit fyrir Krita +Comment[it]=Plugin per gli strumenti per Krita +Comment[ja]=Krita ツールプラグイン +Comment[km]=កម្មវិធី​ជំនួយ​ឧបករណ៍ សម្រាប់ Krita +Comment[ms]=Plugin alat Krita +Comment[nb]=Krita-programtillegg for verktøy +Comment[nds]=Warktüüchmoduul för Krita +Comment[ne]=क्रिताका लागि उपकरण प्लगइन +Comment[nl]=Gereedschapsplugin voor Krita +Comment[nn]=Krita-programtillegg for verktøy +Comment[pl]=Wtyczka narzędzi dla Krita +Comment[pt]='Plugin' de ferramentas do Krita +Comment[pt_BR]=Plugin de ferramenta para o Krita +Comment[ru]=Инструменты Krita +Comment[sk]=Modul nástrojov pre Krita +Comment[sl]=Vstavek z orodjem za Krito +Comment[sr]=Алатни прикључак за Krita-у +Comment[sr@Latn]=Alatni priključak za Krita-u +Comment[sv]=Verktygsinsticksprogram för Krita +Comment[uk]=Втулок інструментів для Krita +Comment[uz]=Krita uchun vosita plagini +Comment[uz@cyrillic]=Krita учун восита плагини +Comment[zh_CN]=Krita 工具插件 +Comment[zh_TW]=Krita 的工具外掛程式 +[PropertyDef::X-Krita-Version] +Type=int diff --git a/krita/data/palettes/40_Colors.gpl b/krita/data/palettes/40_Colors.gpl new file mode 100644 index 00000000..97d98c37 --- /dev/null +++ b/krita/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/krita/data/palettes/Anchor.gpl b/krita/data/palettes/Anchor.gpl new file mode 100644 index 00000000..590838b1 --- /dev/null +++ b/krita/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/krita/data/palettes/Bears.gpl b/krita/data/palettes/Bears.gpl new file mode 100644 index 00000000..189d4cfd --- /dev/null +++ b/krita/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/krita/data/palettes/Bgold.gpl b/krita/data/palettes/Bgold.gpl new file mode 100644 index 00000000..3e8e8068 --- /dev/null +++ b/krita/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/krita/data/palettes/Blues.gpl b/krita/data/palettes/Blues.gpl new file mode 100644 index 00000000..33fcfc08 --- /dev/null +++ b/krita/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/krita/data/palettes/Borders.gpl b/krita/data/palettes/Borders.gpl new file mode 100644 index 00000000..424d6b6d --- /dev/null +++ b/krita/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/krita/data/palettes/Browns_And_Yellows.gpl b/krita/data/palettes/Browns_And_Yellows.gpl new file mode 100644 index 00000000..bd100e27 --- /dev/null +++ b/krita/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/krita/data/palettes/Caramel.gpl b/krita/data/palettes/Caramel.gpl new file mode 100644 index 00000000..2ee783de --- /dev/null +++ b/krita/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/krita/data/palettes/Cascade.gpl b/krita/data/palettes/Cascade.gpl new file mode 100644 index 00000000..1c8e7e59 --- /dev/null +++ b/krita/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/krita/data/palettes/China.gpl b/krita/data/palettes/China.gpl new file mode 100644 index 00000000..670578ad --- /dev/null +++ b/krita/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/krita/data/palettes/Coldfire.gpl b/krita/data/palettes/Coldfire.gpl new file mode 100644 index 00000000..6c25698a --- /dev/null +++ b/krita/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/krita/data/palettes/Cool_Colors.gpl b/krita/data/palettes/Cool_Colors.gpl new file mode 100644 index 00000000..3a1b83a5 --- /dev/null +++ b/krita/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/krita/data/palettes/Cranes.gpl b/krita/data/palettes/Cranes.gpl new file mode 100644 index 00000000..6ea0714e --- /dev/null +++ b/krita/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/krita/data/palettes/DMC.gpl b/krita/data/palettes/DMC.gpl new file mode 100644 index 00000000..7e9a0c0c --- /dev/null +++ b/krita/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/krita/data/palettes/Dark_pastels.gpl b/krita/data/palettes/Dark_pastels.gpl new file mode 100644 index 00000000..3802cd00 --- /dev/null +++ b/krita/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/krita/data/palettes/Default.gpl b/krita/data/palettes/Default.gpl new file mode 100644 index 00000000..b2541c35 --- /dev/null +++ b/krita/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/krita/data/palettes/Ega.gpl b/krita/data/palettes/Ega.gpl new file mode 100644 index 00000000..80b6d06d --- /dev/null +++ b/krita/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/krita/data/palettes/Firecode.gpl b/krita/data/palettes/Firecode.gpl new file mode 100644 index 00000000..252b738e --- /dev/null +++ b/krita/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/krita/data/palettes/Gold.gpl b/krita/data/palettes/Gold.gpl new file mode 100644 index 00000000..86ccca81 --- /dev/null +++ b/krita/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/krita/data/palettes/GrayViolet.gpl b/krita/data/palettes/GrayViolet.gpl new file mode 100644 index 00000000..9bc34021 --- /dev/null +++ b/krita/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/krita/data/palettes/Grayblue.gpl b/krita/data/palettes/Grayblue.gpl new file mode 100644 index 00000000..982749dc --- /dev/null +++ b/krita/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/krita/data/palettes/Grays.gpl b/krita/data/palettes/Grays.gpl new file mode 100644 index 00000000..49050b22 --- /dev/null +++ b/krita/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/krita/data/palettes/Greens.gpl b/krita/data/palettes/Greens.gpl new file mode 100644 index 00000000..9da819b4 --- /dev/null +++ b/krita/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/krita/data/palettes/Hilite.gpl b/krita/data/palettes/Hilite.gpl new file mode 100644 index 00000000..74b28684 --- /dev/null +++ b/krita/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/krita/data/palettes/Khaki.gpl b/krita/data/palettes/Khaki.gpl new file mode 100644 index 00000000..88ea2238 --- /dev/null +++ b/krita/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/krita/data/palettes/Lights.gpl b/krita/data/palettes/Lights.gpl new file mode 100644 index 00000000..d2330496 --- /dev/null +++ b/krita/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/krita/data/palettes/Madeira.gpl b/krita/data/palettes/Madeira.gpl new file mode 100644 index 00000000..fbf7c30a --- /dev/null +++ b/krita/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/krita/data/palettes/Makefile.am b/krita/data/palettes/Makefile.am new file mode 100644 index 00000000..bd0166ca --- /dev/null +++ b/krita/data/palettes/Makefile.am @@ -0,0 +1,50 @@ +kritapalettesdir = $(prefix)/share/apps/krita/palettes + +kritapalettes_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/krita/data/palettes/Muted.gpl b/krita/data/palettes/Muted.gpl new file mode 100644 index 00000000..9d32a02d --- /dev/null +++ b/krita/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/krita/data/palettes/Named_Colors.gpl b/krita/data/palettes/Named_Colors.gpl new file mode 100644 index 00000000..5fbd533b --- /dev/null +++ b/krita/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 moccasin (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/krita/data/palettes/News3.gpl b/krita/data/palettes/News3.gpl new file mode 100644 index 00000000..2fb44378 --- /dev/null +++ b/krita/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/krita/data/palettes/Op2.gpl b/krita/data/palettes/Op2.gpl new file mode 100644 index 00000000..891f1fb4 --- /dev/null +++ b/krita/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/krita/data/palettes/Paintjet.gpl b/krita/data/palettes/Paintjet.gpl new file mode 100644 index 00000000..c061b6c5 --- /dev/null +++ b/krita/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/krita/data/palettes/Pantone_Coated_Approx.gpl b/krita/data/palettes/Pantone_Coated_Approx.gpl new file mode 100644 index 00000000..5ddb0d46 --- /dev/null +++ b/krita/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/krita/data/palettes/Pastels.gpl b/krita/data/palettes/Pastels.gpl new file mode 100644 index 00000000..bcfd9342 --- /dev/null +++ b/krita/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/krita/data/palettes/Plasma.gpl b/krita/data/palettes/Plasma.gpl new file mode 100644 index 00000000..db3982bc --- /dev/null +++ b/krita/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/krita/data/palettes/Reds.gpl b/krita/data/palettes/Reds.gpl new file mode 100644 index 00000000..8297e143 --- /dev/null +++ b/krita/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/krita/data/palettes/Reds_And_Purples.gpl b/krita/data/palettes/Reds_And_Purples.gpl new file mode 100644 index 00000000..6096547c --- /dev/null +++ b/krita/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/krita/data/palettes/Royal.gpl b/krita/data/palettes/Royal.gpl new file mode 100644 index 00000000..67c5bbb7 --- /dev/null +++ b/krita/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/krita/data/palettes/Topographic.gpl b/krita/data/palettes/Topographic.gpl new file mode 100644 index 00000000..8361edc7 --- /dev/null +++ b/krita/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/krita/data/palettes/Visibone.gpl b/krita/data/palettes/Visibone.gpl new file mode 100644 index 00000000..17c357b9 --- /dev/null +++ b/krita/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/krita/data/palettes/Visibone_2.gpl b/krita/data/palettes/Visibone_2.gpl new file mode 100644 index 00000000..affacd18 --- /dev/null +++ b/krita/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/krita/data/palettes/Volcano.gpl b/krita/data/palettes/Volcano.gpl new file mode 100644 index 00000000..f9031e3d --- /dev/null +++ b/krita/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/krita/data/palettes/Warm_Colors.gpl b/krita/data/palettes/Warm_Colors.gpl new file mode 100644 index 00000000..654ad5da --- /dev/null +++ b/krita/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/krita/data/palettes/Web.gpl b/krita/data/palettes/Web.gpl new file mode 100644 index 00000000..0b907f79 --- /dev/null +++ b/krita/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/krita/data/palettes/new_kde.gpl b/krita/data/palettes/new_kde.gpl new file mode 100644 index 00000000..33647606 --- /dev/null +++ b/krita/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/krita/data/patterns/3dgreen.pat b/krita/data/patterns/3dgreen.pat new file mode 100644 index 00000000..763f912b Binary files /dev/null and b/krita/data/patterns/3dgreen.pat differ diff --git a/krita/data/patterns/Craters.pat b/krita/data/patterns/Craters.pat new file mode 100644 index 00000000..4590349d Binary files /dev/null and b/krita/data/patterns/Craters.pat differ diff --git a/krita/data/patterns/Makefile.am b/krita/data/patterns/Makefile.am new file mode 100644 index 00000000..4b95bf03 --- /dev/null +++ b/krita/data/patterns/Makefile.am @@ -0,0 +1,5 @@ + +kritapatternsdir = $(prefix)/share/apps/krita/patterns + +kritapatterns_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/krita/data/patterns/Moonfoot.pat b/krita/data/patterns/Moonfoot.pat new file mode 100644 index 00000000..4c9236c6 Binary files /dev/null and b/krita/data/patterns/Moonfoot.pat differ diff --git a/krita/data/patterns/Stripes1px.pat b/krita/data/patterns/Stripes1px.pat new file mode 100644 index 00000000..ddfd0c70 Binary files /dev/null and b/krita/data/patterns/Stripes1px.pat differ diff --git a/krita/data/patterns/Stripes2px.pat b/krita/data/patterns/Stripes2px.pat new file mode 100644 index 00000000..411e1b34 Binary files /dev/null and b/krita/data/patterns/Stripes2px.pat differ diff --git a/krita/data/patterns/amethyst.pat b/krita/data/patterns/amethyst.pat new file mode 100644 index 00000000..f83eb861 Binary files /dev/null and b/krita/data/patterns/amethyst.pat differ diff --git a/krita/data/patterns/bark.pat b/krita/data/patterns/bark.pat new file mode 100644 index 00000000..ba137b12 Binary files /dev/null and b/krita/data/patterns/bark.pat differ diff --git a/krita/data/patterns/blue.pat b/krita/data/patterns/blue.pat new file mode 100644 index 00000000..f1320954 Binary files /dev/null and b/krita/data/patterns/blue.pat differ diff --git a/krita/data/patterns/bluegrid.pat b/krita/data/patterns/bluegrid.pat new file mode 100644 index 00000000..33bf092c Binary files /dev/null and b/krita/data/patterns/bluegrid.pat differ diff --git a/krita/data/patterns/bluesquares.pat b/krita/data/patterns/bluesquares.pat new file mode 100644 index 00000000..2bce749f Binary files /dev/null and b/krita/data/patterns/bluesquares.pat differ diff --git a/krita/data/patterns/blueweb.pat b/krita/data/patterns/blueweb.pat new file mode 100644 index 00000000..fce2c1f6 Binary files /dev/null and b/krita/data/patterns/blueweb.pat differ diff --git a/krita/data/patterns/brick.pat b/krita/data/patterns/brick.pat new file mode 100644 index 00000000..9e018230 Binary files /dev/null and b/krita/data/patterns/brick.pat differ diff --git a/krita/data/patterns/burlap.pat b/krita/data/patterns/burlap.pat new file mode 100644 index 00000000..f2fc3c4e Binary files /dev/null and b/krita/data/patterns/burlap.pat differ diff --git a/krita/data/patterns/burlwood.pat b/krita/data/patterns/burlwood.pat new file mode 100644 index 00000000..2d89ba14 Binary files /dev/null and b/krita/data/patterns/burlwood.pat differ diff --git a/krita/data/patterns/choc_swirl.pat b/krita/data/patterns/choc_swirl.pat new file mode 100644 index 00000000..b6551129 Binary files /dev/null and b/krita/data/patterns/choc_swirl.pat differ diff --git a/krita/data/patterns/corkboard.pat b/krita/data/patterns/corkboard.pat new file mode 100644 index 00000000..ffb912e5 Binary files /dev/null and b/krita/data/patterns/corkboard.pat differ diff --git a/krita/data/patterns/cracked.pat b/krita/data/patterns/cracked.pat new file mode 100644 index 00000000..a13cc556 Binary files /dev/null and b/krita/data/patterns/cracked.pat differ diff --git a/krita/data/patterns/crinklepaper.pat b/krita/data/patterns/crinklepaper.pat new file mode 100644 index 00000000..2efa9f76 Binary files /dev/null and b/krita/data/patterns/crinklepaper.pat differ diff --git a/krita/data/patterns/electric.pat b/krita/data/patterns/electric.pat new file mode 100644 index 00000000..34263300 Binary files /dev/null and b/krita/data/patterns/electric.pat differ diff --git a/krita/data/patterns/fibers.pat b/krita/data/patterns/fibers.pat new file mode 100644 index 00000000..66d74337 Binary files /dev/null and b/krita/data/patterns/fibers.pat differ diff --git a/krita/data/patterns/granite1.pat b/krita/data/patterns/granite1.pat new file mode 100644 index 00000000..e798a389 Binary files /dev/null and b/krita/data/patterns/granite1.pat differ diff --git a/krita/data/patterns/ground1.pat b/krita/data/patterns/ground1.pat new file mode 100644 index 00000000..88874598 Binary files /dev/null and b/krita/data/patterns/ground1.pat differ diff --git a/krita/data/patterns/ice.pat b/krita/data/patterns/ice.pat new file mode 100644 index 00000000..ffb8439f Binary files /dev/null and b/krita/data/patterns/ice.pat differ diff --git a/krita/data/patterns/java.pat b/krita/data/patterns/java.pat new file mode 100644 index 00000000..60f8d2ca Binary files /dev/null and b/krita/data/patterns/java.pat differ diff --git a/krita/data/patterns/leather.pat b/krita/data/patterns/leather.pat new file mode 100644 index 00000000..133c9c15 Binary files /dev/null and b/krita/data/patterns/leather.pat differ diff --git a/krita/data/patterns/leaves.pat b/krita/data/patterns/leaves.pat new file mode 100644 index 00000000..6ebdeba0 Binary files /dev/null and b/krita/data/patterns/leaves.pat differ diff --git a/krita/data/patterns/leopard.pat b/krita/data/patterns/leopard.pat new file mode 100644 index 00000000..62f780b6 Binary files /dev/null and b/krita/data/patterns/leopard.pat differ diff --git a/krita/data/patterns/lightning.pat b/krita/data/patterns/lightning.pat new file mode 100644 index 00000000..1e022676 Binary files /dev/null and b/krita/data/patterns/lightning.pat differ diff --git a/krita/data/patterns/marble1.pat b/krita/data/patterns/marble1.pat new file mode 100644 index 00000000..7be031b1 Binary files /dev/null and b/krita/data/patterns/marble1.pat differ diff --git a/krita/data/patterns/marble2.pat b/krita/data/patterns/marble2.pat new file mode 100644 index 00000000..447c32df Binary files /dev/null and b/krita/data/patterns/marble2.pat differ diff --git a/krita/data/patterns/marble3.pat b/krita/data/patterns/marble3.pat new file mode 100644 index 00000000..c3b57e97 Binary files /dev/null and b/krita/data/patterns/marble3.pat differ diff --git a/krita/data/patterns/nops.pat b/krita/data/patterns/nops.pat new file mode 100644 index 00000000..5fbef16d Binary files /dev/null and b/krita/data/patterns/nops.pat differ diff --git a/krita/data/patterns/paper.pat b/krita/data/patterns/paper.pat new file mode 100644 index 00000000..26fa0263 Binary files /dev/null and b/krita/data/patterns/paper.pat differ diff --git a/krita/data/patterns/parque1.pat b/krita/data/patterns/parque1.pat new file mode 100644 index 00000000..d647761b Binary files /dev/null and b/krita/data/patterns/parque1.pat differ diff --git a/krita/data/patterns/parque2.pat b/krita/data/patterns/parque2.pat new file mode 100644 index 00000000..0d493c6a Binary files /dev/null and b/krita/data/patterns/parque2.pat differ diff --git a/krita/data/patterns/parque3.pat b/krita/data/patterns/parque3.pat new file mode 100644 index 00000000..aa43ec0d Binary files /dev/null and b/krita/data/patterns/parque3.pat differ diff --git a/krita/data/patterns/pastel.pat b/krita/data/patterns/pastel.pat new file mode 100644 index 00000000..09b3efb1 Binary files /dev/null and b/krita/data/patterns/pastel.pat differ diff --git a/krita/data/patterns/pine.pat b/krita/data/patterns/pine.pat new file mode 100644 index 00000000..284d7b4e Binary files /dev/null and b/krita/data/patterns/pine.pat differ diff --git a/krita/data/patterns/pink_marble.pat b/krita/data/patterns/pink_marble.pat new file mode 100644 index 00000000..03b4060c Binary files /dev/null and b/krita/data/patterns/pink_marble.pat differ diff --git a/krita/data/patterns/pool.pat b/krita/data/patterns/pool.pat new file mode 100644 index 00000000..748f9fa1 Binary files /dev/null and b/krita/data/patterns/pool.pat differ diff --git a/krita/data/patterns/qube1.pat b/krita/data/patterns/qube1.pat new file mode 100644 index 00000000..de49fb2a Binary files /dev/null and b/krita/data/patterns/qube1.pat differ diff --git a/krita/data/patterns/rain.pat b/krita/data/patterns/rain.pat new file mode 100644 index 00000000..d00aadb2 Binary files /dev/null and b/krita/data/patterns/rain.pat differ diff --git a/krita/data/patterns/recessed.pat b/krita/data/patterns/recessed.pat new file mode 100644 index 00000000..04d86f37 Binary files /dev/null and b/krita/data/patterns/recessed.pat differ diff --git a/krita/data/patterns/redcube.pat b/krita/data/patterns/redcube.pat new file mode 100644 index 00000000..7411b558 Binary files /dev/null and b/krita/data/patterns/redcube.pat differ diff --git a/krita/data/patterns/rock.pat b/krita/data/patterns/rock.pat new file mode 100644 index 00000000..8c545fd2 Binary files /dev/null and b/krita/data/patterns/rock.pat differ diff --git a/krita/data/patterns/sky.pat b/krita/data/patterns/sky.pat new file mode 100644 index 00000000..0add1646 Binary files /dev/null and b/krita/data/patterns/sky.pat differ diff --git a/krita/data/patterns/slate.pat b/krita/data/patterns/slate.pat new file mode 100644 index 00000000..152da130 Binary files /dev/null and b/krita/data/patterns/slate.pat differ diff --git a/krita/data/patterns/sm_squares.pat b/krita/data/patterns/sm_squares.pat new file mode 100644 index 00000000..93ddc976 Binary files /dev/null and b/krita/data/patterns/sm_squares.pat differ diff --git a/krita/data/patterns/starfield.pat b/krita/data/patterns/starfield.pat new file mode 100644 index 00000000..f53ba402 Binary files /dev/null and b/krita/data/patterns/starfield.pat differ diff --git a/krita/data/patterns/stone33.pat b/krita/data/patterns/stone33.pat new file mode 100644 index 00000000..08646912 Binary files /dev/null and b/krita/data/patterns/stone33.pat differ diff --git a/krita/data/patterns/terra.pat b/krita/data/patterns/terra.pat new file mode 100644 index 00000000..79bc2ec4 Binary files /dev/null and b/krita/data/patterns/terra.pat differ diff --git a/krita/data/patterns/walnut.pat b/krita/data/patterns/walnut.pat new file mode 100644 index 00000000..7007dd81 Binary files /dev/null and b/krita/data/patterns/walnut.pat differ diff --git a/krita/data/patterns/warning.pat b/krita/data/patterns/warning.pat new file mode 100644 index 00000000..a62d98ad Binary files /dev/null and b/krita/data/patterns/warning.pat differ diff --git a/krita/data/patterns/wood1.pat b/krita/data/patterns/wood1.pat new file mode 100644 index 00000000..07fa24ca Binary files /dev/null and b/krita/data/patterns/wood1.pat differ diff --git a/krita/data/patterns/wood2.pat b/krita/data/patterns/wood2.pat new file mode 100644 index 00000000..7da760e6 Binary files /dev/null and b/krita/data/patterns/wood2.pat differ diff --git a/krita/data/patterns/wood3.pat b/krita/data/patterns/wood3.pat new file mode 100644 index 00000000..0712c2de Binary files /dev/null and b/krita/data/patterns/wood3.pat differ diff --git a/krita/data/patterns/wood4.pat b/krita/data/patterns/wood4.pat new file mode 100644 index 00000000..1fc27822 Binary files /dev/null and b/krita/data/patterns/wood4.pat differ diff --git a/krita/data/patterns/wood5.pat b/krita/data/patterns/wood5.pat new file mode 100644 index 00000000..5f415ce6 Binary files /dev/null and b/krita/data/patterns/wood5.pat differ diff --git a/krita/data/profiles/Adobe.icm b/krita/data/profiles/Adobe.icm new file mode 100644 index 00000000..ae368c6d Binary files /dev/null and b/krita/data/profiles/Adobe.icm differ diff --git a/krita/data/profiles/Apple.icm b/krita/data/profiles/Apple.icm new file mode 100644 index 00000000..6113a226 Binary files /dev/null and b/krita/data/profiles/Apple.icm differ diff --git a/krita/data/profiles/CIE.icm b/krita/data/profiles/CIE.icm new file mode 100644 index 00000000..bd5e20a8 Binary files /dev/null and b/krita/data/profiles/CIE.icm differ diff --git a/krita/data/profiles/CMY.icm b/krita/data/profiles/CMY.icm new file mode 100644 index 00000000..acc71ddd Binary files /dev/null and b/krita/data/profiles/CMY.icm differ diff --git a/krita/data/profiles/ColorMatch.icm b/krita/data/profiles/ColorMatch.icm new file mode 100644 index 00000000..d1c1a1f8 Binary files /dev/null and b/krita/data/profiles/ColorMatch.icm differ diff --git a/krita/data/profiles/Makefile.am b/krita/data/profiles/Makefile.am new file mode 100644 index 00000000..e42f1dbb --- /dev/null +++ b/krita/data/profiles/Makefile.am @@ -0,0 +1,4 @@ + +kritaprofilesdir = $(prefix)/share/apps/krita/profiles + +kritaprofiles_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/krita/data/profiles/NTSC.icm b/krita/data/profiles/NTSC.icm new file mode 100644 index 00000000..abe4dcfb Binary files /dev/null and b/krita/data/profiles/NTSC.icm differ diff --git a/krita/data/profiles/PAL.icm b/krita/data/profiles/PAL.icm new file mode 100644 index 00000000..173a0d2b Binary files /dev/null and b/krita/data/profiles/PAL.icm differ diff --git a/krita/data/profiles/README b/krita/data/profiles/README new file mode 100644 index 00000000..f0a75798 --- /dev/null +++ b/krita/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/krita/data/profiles/SMPTE-C.icm b/krita/data/profiles/SMPTE-C.icm new file mode 100644 index 00000000..7f4ef578 Binary files /dev/null and b/krita/data/profiles/SMPTE-C.icm differ diff --git a/krita/data/profiles/WideGamut.icm b/krita/data/profiles/WideGamut.icm new file mode 100644 index 00000000..120a99a1 Binary files /dev/null and b/krita/data/profiles/WideGamut.icm differ diff --git a/krita/data/profiles/cmyk.icm b/krita/data/profiles/cmyk.icm new file mode 100644 index 00000000..eb24bcca Binary files /dev/null and b/krita/data/profiles/cmyk.icm differ diff --git a/krita/data/profiles/fogra27l.icm b/krita/data/profiles/fogra27l.icm new file mode 100644 index 00000000..3aad9760 Binary files /dev/null and b/krita/data/profiles/fogra27l.icm differ diff --git a/krita/data/profiles/lcmslabi.icm b/krita/data/profiles/lcmslabi.icm new file mode 100644 index 00000000..f86821b5 Binary files /dev/null and b/krita/data/profiles/lcmslabi.icm differ diff --git a/krita/data/profiles/lcmsxyzi.icm b/krita/data/profiles/lcmsxyzi.icm new file mode 100644 index 00000000..099006aa Binary files /dev/null and b/krita/data/profiles/lcmsxyzi.icm differ diff --git a/krita/data/profiles/monoscnr.icm b/krita/data/profiles/monoscnr.icm new file mode 100644 index 00000000..411a9728 Binary files /dev/null and b/krita/data/profiles/monoscnr.icm differ diff --git a/krita/data/profiles/sRGB.icm b/krita/data/profiles/sRGB.icm new file mode 100644 index 00000000..878fdf12 Binary files /dev/null and b/krita/data/profiles/sRGB.icm differ diff --git a/krita/data/profiles/srgb_color_space_profile.icm b/krita/data/profiles/srgb_color_space_profile.icm new file mode 100644 index 00000000..7f9d18d0 Binary files /dev/null and b/krita/data/profiles/srgb_color_space_profile.icm differ diff --git a/krita/data/profiles/srgbspac.icm b/krita/data/profiles/srgbspac.icm new file mode 100644 index 00000000..83563ef9 Binary files /dev/null and b/krita/data/profiles/srgbspac.icm differ diff --git a/krita/data/profiles/tifflab8spac.icm b/krita/data/profiles/tifflab8spac.icm new file mode 100644 index 00000000..0b6543cc Binary files /dev/null and b/krita/data/profiles/tifflab8spac.icm differ diff --git a/krita/data/profiles/ycc601.icm b/krita/data/profiles/ycc601.icm new file mode 100644 index 00000000..7ee086db Binary files /dev/null and b/krita/data/profiles/ycc601.icm differ diff --git a/krita/data/profiles/ycc709.icm b/krita/data/profiles/ycc709.icm new file mode 100644 index 00000000..d9f5a5a5 Binary files /dev/null and b/krita/data/profiles/ycc709.icm differ diff --git a/krita/data/templates/.directory b/krita/data/templates/.directory new file mode 100644 index 00000000..66f4bc3c --- /dev/null +++ b/krita/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/krita/design.h b/krita/design.h new file mode 100644 index 00000000..2f7db402 --- /dev/null +++ b/krita/design.h @@ -0,0 +1,27 @@ +/** + @mainpage Krita Image manipulation and paint application + + Krita is an advanced and modular paint and image manipulation + application. + + Krita is built around two core libraries: kritacolor and kritaimage. + + The kritacolor 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 kritaimage 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/krita/doc/DESIGN.obsolete b/krita/doc/DESIGN.obsolete new file mode 100644 index 00000000..f3fd1631 --- /dev/null +++ b/krita/doc/DESIGN.obsolete @@ -0,0 +1,179 @@ +A Perspective on Krita's Design + + Krita'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 Krita used + namespaces, one fancies), then became Krayon to end up as Krita. 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 krita 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 Krita to use a lot design patterns. Krita + 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 shapes, + patterns (and colours, too?) Patrick intended a Flyweight + here. + + * The composite pattern is used in paint devices, layers, channels, + etc. (What about masks?) + + * 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 .krita. 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 krita objects: image, paintdevice, channel, + mask, 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 + + Krita 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 krita 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_mask + 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_mask 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 krita color channel + bit depth independent. + + + - Is KisVector only used in obsolete tools? + + - I take it that the two tests that are present in krita/test + are obsolete? + + - what with the dummmmmy.cc? + + - which bits of the krita/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/krita/doc/Developing Krita Plugins.odt b/krita/doc/Developing Krita Plugins.odt new file mode 100644 index 00000000..1e74bff8 Binary files /dev/null and b/krita/doc/Developing Krita Plugins.odt differ diff --git a/krita/doc/autoextending paintdevices b/krita/doc/autoextending paintdevices new file mode 100644 index 00000000..a42dc683 --- /dev/null +++ b/krita/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/krita/doc/background_paper.txt b/krita/doc/background_paper.txt new file mode 100644 index 00000000..c70f6dd6 --- /dev/null +++ b/krita/doc/background_paper.txt @@ -0,0 +1,84 @@ +Background, paper, layers, blobs + +An image in Krita 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 masks, 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 shape cursors. + + diff --git a/krita/doc/brush.txt b/krita/doc/brush.txt new file mode 100644 index 00000000..bd310ee0 --- /dev/null +++ b/krita/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 Krita, I felt I needed examples. I used the following +sources: + +* The old Krita brush code (http://webcvs.kde.org/cgi-bin/cvsweb.cgi/koffice/krita/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 find) (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) + +Krita 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 mask: 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 masked -- 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 masks 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 mask of a brush is however by now pretty well done; the next +problem is painting with those masks. + +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 +mask 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/krita/doc/channels_masks_selections b/krita/doc/channels_masks_selections new file mode 100644 index 00000000..837e154e --- /dev/null +++ b/krita/doc/channels_masks_selections @@ -0,0 +1,12 @@ +We did a rethink on channels, selections and masks last summer. + +Traditionally, a mask 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/krita/doc/colordiff b/krita/doc/colordiff new file mode 100644 index 00000000..b84a98fa --- /dev/null +++ b/krita/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/krita/doc/colorspaces.xmi b/krita/doc/colorspaces.xmi new file mode 100644 index 00000000..107e3445 --- /dev/null +++ b/krita/doc/colorspaces.xmi @@ -0,0 +1,41965 @@ + + + + + umbrello uml modeller http://uml.sf.net + 1.4.2 + UnicodeUTF8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ +
+ +
+
+
+ +
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+
+ + + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + +
+ +
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+
+
+
+
diff --git a/krita/doc/colorstrategyAPI b/krita/doc/colorstrategyAPI new file mode 100644 index 00000000..bb6e1267 --- /dev/null +++ b/krita/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 mask 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 mask) +{ + QRect r = mask -> extent(); + crop(r); + + for (Q_INT32 y = r.top(); y <= r.bottom(); ++y) { + + KisHLineIterator pixelIt = createHLineIterator(r.x(), y, r.width(), true); + KisHLineIterator maskIt = mask -> createHLineIterator(r.x(), y, r.width(), false); + + while (!pixelIt.isDone()) { + + KisPixel pixel = toPixel(pixelIt.rawData()); + KisPixel maskValue = mask -> toPixel(maskIt.rawData()); + + pixel.alpha() = (pixel.alpha() * maskValue.alpha()) / MAX_SELECTED; + + ++pixelIt; + ++maskIt; + } + } +} + diff --git a/krita/doc/controller.xmi b/krita/doc/controller.xmi new file mode 100644 index 00000000..2bdf079e --- /dev/null +++ b/krita/doc/controller.xmi @@ -0,0 +1,39776 @@ + + + + + umbrello uml modeller http://uml.sf.net + 1.4 + UnicodeUTF8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ +
+ +
+
+
+ +
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+
+
+
+
diff --git a/krita/doc/coordinates.txt b/krita/doc/coordinates.txt new file mode 100644 index 00000000..3518faee --- /dev/null +++ b/krita/doc/coordinates.txt @@ -0,0 +1,9 @@ +Coordinates in Krita + +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/krita/doc/dirty.txt b/krita/doc/dirty.txt new file mode 100644 index 00000000..91a870bf --- /dev/null +++ b/krita/doc/dirty.txt @@ -0,0 +1,53 @@ +Dirty marking and rendering + +Krita 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/krita/doc/doc-outline b/krita/doc/doc-outline new file mode 100644 index 00000000..6f974db6 --- /dev/null +++ b/krita/doc/doc-outline @@ -0,0 +1,187 @@ +Krita 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 Krita" 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 Krita's documentation. It +is based on the Krita manual in SVN (koffice/krita/doc/manual/krita.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 Krita + - Key features + - Color management + - File formats + - About this manual + - About the application author + +- Tutorial + - Starting to know Krita (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 Krita'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 masks + - 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 layout + - 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 Krita + - Key features + - Color management + - File formats + - About this manual + - About the application author + +- Tutorial + - Starting to know Krita (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 layout + - Menus + - Toolbars + - Palettes + - Dialogs + +- Settings + +- Scripting + +- FAQ + +- Credits + +- Installation + +---------------------------------------------------------------------- + +An outline of the manual content as in krita.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 Krita +- Configuring Krita +- Help! + - Help contact info + + diff --git a/krita/doc/histograms.xmi b/krita/doc/histograms.xmi new file mode 100644 index 00000000..c7ff1428 --- /dev/null +++ b/krita/doc/histograms.xmi @@ -0,0 +1,4145 @@ + + + + + umbrello uml modeller http://uml.sf.net + 1.4.2 + UnicodeUTF8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/krita/doc/hooks b/krita/doc/hooks new file mode 100644 index 00000000..27653a2f --- /dev/null +++ b/krita/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 mask 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 +Krita 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/krita/doc/howtofilters.txt b/krita/doc/howtofilters.txt new file mode 100644 index 00000000..6fca2fc8 --- /dev/null +++ b/krita/doc/howtofilters.txt @@ -0,0 +1,30 @@ +The goal of this howto is to explain how to create a filter for krita + + +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/krita/doc/impexp.txt b/krita/doc/impexp.txt new file mode 100644 index 00000000..f23fdb5a --- /dev/null +++ b/krita/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 Krita 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 Krita pixels and must + unpack krita 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/krita/doc/krita-features b/krita/doc/krita-features new file mode 100644 index 00000000..985b2698 --- /dev/null +++ b/krita/doc/krita-features @@ -0,0 +1,215 @@ +Krita Features + +The following is a comprehensive list of all Krita's features +that are or will be implemented for version 1.5. + +* Plugins + +Krita 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 + +Krita 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. + +Krita's native file format stores icc and exif information. + +* Color models + +Krita 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, Krita 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 + +Krita can multithread the operation of some filters. Krita'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 + +Krita'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 shapes. Support for colored and grayscale brushes and + pipe brushes. Support from Gimp parasites in brushes. +** custom brush shapes +** text brush shapes +** brushes created from layers or images. These brushes can be saved +** colored brushes can also be used as masks + +* Fills + +** gimp-style patterns +** gimp-style gradients +** custom gradients \ No newline at end of file diff --git a/krita/doc/krita.kpr b/krita/doc/krita.kpr new file mode 100644 index 00000000..b1fe023e Binary files /dev/null and b/krita/doc/krita.kpr differ diff --git a/krita/doc/krita.pdf b/krita/doc/krita.pdf new file mode 100644 index 00000000..ddde5dc4 Binary files /dev/null and b/krita/doc/krita.pdf differ diff --git a/krita/doc/krita.xmi b/krita/doc/krita.xmi new file mode 100644 index 00000000..43418ae1 --- /dev/null +++ b/krita/doc/krita.xmi @@ -0,0 +1,56432 @@ + + + + + umbrello uml modeller http://uml.sf.net + 1.2.0 + UnicodeUTF8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + +
+ +
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
diff --git a/krita/doc/large_files b/krita/doc/large_files new file mode 100644 index 00000000..96d43227 --- /dev/null +++ b/krita/doc/large_files @@ -0,0 +1,36 @@ +One think Krita can not handle are really big files. A 125MB tif file is +loading into memory in one go, making Krita take about 289MB of memory +-- with no image loaded, Krita takes a more reasonable 41MB. And during +loading, Krita 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 krita +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 Krita'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 Krita 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/krita/doc/layersupdatesignals.flw b/krita/doc/layersupdatesignals.flw new file mode 100644 index 00000000..7f7a66c5 Binary files /dev/null and b/krita/doc/layersupdatesignals.flw differ diff --git a/krita/doc/manual/krita.kwd b/krita/doc/manual/krita.kwd new file mode 100644 index 00000000..d076bfc6 Binary files /dev/null and b/krita/doc/manual/krita.kwd differ diff --git a/krita/doc/oasis b/krita/doc/oasis new file mode 100644 index 00000000..93b443b8 --- /dev/null +++ b/krita/doc/oasis @@ -0,0 +1,5 @@ +Krita 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/krita/doc/paint_device.txt b/krita/doc/paint_device.txt new file mode 100644 index 00000000..b68979dc --- /dev/null +++ b/krita/doc/paint_device.txt @@ -0,0 +1,98 @@ +THIS DOCUMENT IS OBSOLETED BY THE AUTOLAYERS MERGE + +* Paint devices and painters + +Krita'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. + +Krita 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 krita 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), apparently. + + 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. Krita, 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/krita/doc/palettedesign.txt b/krita/doc/palettedesign.txt new file mode 100644 index 00000000..549264a7 --- /dev/null +++ b/krita/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 signals and 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/krita/doc/plugins.txt b/krita/doc/plugins.txt new file mode 100644 index 00000000..1aa5dfce --- /dev/null +++ b/krita/doc/plugins.txt @@ -0,0 +1,32 @@ +There are several kinds of plugins in Krita: CoreModules and Plugins. Core modules +add functionality to Krita 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 Krita (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. + + +Krita 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/krita/doc/profiles.txt b/krita/doc/profiles.txt new file mode 100644 index 00000000..fb904748 --- /dev/null +++ b/krita/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 Krita: + +Image profile The image profile is the default profile + for the default color space for the layers + in Krita + +Layer profile Krita 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 Krita 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 Krita 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: Krita 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 Krita 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 Krita + 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 Krita'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 + Krita file. That should be easy, since a Krita + file is just a zipfile. + +File saving When loading a Krita file format image we + should also be able to load embedded profiles. + + +* Krita 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 Krita, but it needs to be done + some time. XXX: Ask the KGamma developers about this? + + diff --git a/krita/doc/resolution.txt b/krita/doc/resolution.txt new file mode 100644 index 00000000..ac4ced7f --- /dev/null +++ b/krita/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/krita/doc/scripts/dcop.py b/krita/doc/scripts/dcop.py new file mode 100644 index 00000000..3a53f999 --- /dev/null +++ b/krita/doc/scripts/dcop.py @@ -0,0 +1,14 @@ +from pydcop import * + +app = "" +for a in apps(): + if (a.startswith("krita")): + 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/krita/doc/sdk b/krita/doc/sdk new file mode 100644 index 00000000..6ca1fbe9 --- /dev/null +++ b/krita/doc/sdk @@ -0,0 +1,10 @@ +Krita SDK + +The Krita SDK is in development. Basically, plugins and extensions should +not include anything from krita/core, but only the headers from krita/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 parent class of a plugin should +implement the various factory interfaces for paint devices, images and layers. diff --git a/krita/doc/selections b/krita/doc/selections new file mode 100644 index 00000000..4db934fc --- /dev/null +++ b/krita/doc/selections @@ -0,0 +1,127 @@ +Selections in Krita + +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 Krita are special paint devices as big as their parent +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 mask 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 mask 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 shape 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/krita/doc/the preview widget b/krita/doc/the preview widget new file mode 100644 index 00000000..a403da86 --- /dev/null +++ b/krita/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 layout 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/krita/doc/transform_undo.txt b/krita/doc/transform_undo.txt new file mode 100644 index 00000000..fa960655 --- /dev/null +++ b/krita/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/krita/dtd/Makefile.am b/krita/dtd/Makefile.am new file mode 100644 index 00000000..242528b9 --- /dev/null +++ b/krita/dtd/Makefile.am @@ -0,0 +1,4 @@ +dtd_DATA = krita.dtd + +dtddir = $(kde_datadir)/krita/dtd + diff --git a/krita/dtd/krita.dtd b/krita/dtd/krita.dtd new file mode 100644 index 00000000..2e413605 --- /dev/null +++ b/krita/dtd/krita.dtd @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/krita/extracti18n.pl b/krita/extracti18n.pl new file mode 100755 index 00000000..d1d1b591 --- /dev/null +++ b/krita/extracti18n.pl @@ -0,0 +1,90 @@ +#!/usr/bin/perl -w + +# This file is part of Krita +# +# 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/krita/krita.desktop b/krita/krita.desktop new file mode 100644 index 00000000..ce1a2332 --- /dev/null +++ b/krita/krita.desktop @@ -0,0 +1,95 @@ +[Desktop Entry] +Name=Krita +Name[hi]=के-रिता +Name[km]= Krita +Name[lo]=ກຣິຕາ +Name[ne]=क्रिता +Exec=krita %U +DocPath=krita/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-krita +Type=Application +Icon=krita +Categories=Qt;KDE;Graphics; +X-KDE-NativeMimeType=application/x-krita +X-KDE-StartupNotify=true +X-DCOP-ServiceType=Multi +X-Krita-Version=2 diff --git a/krita/krita.rc b/krita/krita.rc new file mode 100644 index 00000000..5a5798d1 --- /dev/null +++ b/krita/krita.rc @@ -0,0 +1,199 @@ + + + + &Edit + + + + + + + + + + + + + + + + &Resources + + + + + + &View + + + + + + + + + + + + + + + + + Grid Spacing + + + + + + + + + + + + + + + + + +&Image + + + + + +&Layer + New + + + + + + + + + + + + + Mask + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Sele&ct + + + + + + + + + + + + +Filte&r + + + + + + + + + + + + + + + +&Tools + + + +Settings + + + + + + +Edit + + + + + + + + + + +Navigation + + + + + + + Krita + + + + Brushes and Stuff + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/krita/krita_part_init.cc b/krita/krita_part_init.cc new file mode 100644 index 00000000..d88b9bb3 --- /dev/null +++ b/krita/krita_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( libkritapart, KisFactory ) diff --git a/krita/krita_readonly.rc b/krita/krita_readonly.rc new file mode 100644 index 00000000..6a827bf2 --- /dev/null +++ b/krita/krita_readonly.rc @@ -0,0 +1,35 @@ + + + + Edit + + + + + + + + + View + + + + +Layer + + + + + + + +Edit + + + +Navigation + + + + + diff --git a/krita/kritacolor/Makefile.am b/krita/kritacolor/Makefile.am new file mode 100644 index 00000000..e51e13d9 --- /dev/null +++ b/krita/kritacolor/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 = libkritacolor.la + +if have_openexr +OPENEXR_SOURCES=kis_f16half_base_colorspace.cc +endif + +libkritacolor_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) + +libkritacolor_la_LDFLAGS = -version-info 1:0:0 -no-undefined $(all_libraries) +libkritacolor_la_LIBADD = colorspaces/libkritacolorspaces.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 = krita_colorspace.desktop + +METASOURCES = AUTO + + diff --git a/krita/kritacolor/README b/krita/kritacolor/README new file mode 100644 index 00000000..f80e0520 --- /dev/null +++ b/krita/kritacolor/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/krita/kritacolor/TODO b/krita/kritacolor/TODO new file mode 100644 index 00000000..70f0bdb3 --- /dev/null +++ b/krita/kritacolor/TODO @@ -0,0 +1,11 @@ +This library is still dependent upon krita/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/krita/kritacolor/colorspaces/Makefile.am b/krita/kritacolor/colorspaces/Makefile.am new file mode 100644 index 00000000..dce96757 --- /dev/null +++ b/krita/kritacolor/colorspaces/Makefile.am @@ -0,0 +1,20 @@ +INCLUDES = -I$(srcdir)/.. \ + -I$(srcdir)/../../sdk \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +noinst_LTLIBRARIES = libkritacolorspaces.la + +libkritacolorspaces_la_SOURCES = \ + kis_alpha_colorspace.cc \ + kis_lab_colorspace.cc + +noinst_HEADERS = \ + kis_alpha_colorspace.h \ + kis_lab_colorspace.h + +libkritacolorspaces_la_LIBADD = $(OPENEXR_LIBS) + +libkritacolorspaces_la_METASOURCES = AUTO + + diff --git a/krita/kritacolor/colorspaces/kis_alpha_colorspace.cc b/krita/kritacolor/colorspaces/kis_alpha_colorspace.cc new file mode 100644 index 00000000..01f8ec00 --- /dev/null +++ b/krita/kritacolor/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 Q_UINT8 PIXEL_MASK = 0; +} + +KisAlphaColorSpace::KisAlphaColorSpace(KisColorSpaceFactoryRegistry * parent, + KisProfile *p) : + KisU8BaseColorSpace(KisID("ALPHA", i18n("Alpha mask")), TYPE_GRAY_8, icSigGrayData, parent, p) +{ + m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), 0, KisChannelInfo::ALPHA, KisChannelInfo::UINT8)); + m_alphaPos = 0; +} + +KisAlphaColorSpace::~KisAlphaColorSpace() +{ +} + +void KisAlphaColorSpace::fromQColor(const QColor& /*c*/, Q_UINT8 *dst, KisProfile * /*profile*/) +{ + dst[PIXEL_MASK] = OPACITY_OPAQUE; +} + +void KisAlphaColorSpace::fromQColor(const QColor& /*c*/, Q_UINT8 opacity, Q_UINT8 *dst, KisProfile * /*profile*/) +{ + dst[PIXEL_MASK] = opacity; +} + +void KisAlphaColorSpace::getAlpha(const Q_UINT8 *pixel, Q_UINT8 *alpha) const +{ + *alpha = *pixel; +} + +void KisAlphaColorSpace::toQColor(const Q_UINT8 */*src*/, QColor *c, KisProfile * /*profile*/) +{ + c->setRgb(255, 255, 255); +} + +void KisAlphaColorSpace::toQColor(const Q_UINT8 *src, QColor *c, Q_UINT8 *opacity, KisProfile * /*profile*/) +{ + c->setRgb(255, 255, 255); + *opacity = src[PIXEL_MASK]; +} + +Q_UINT8 KisAlphaColorSpace::difference(const Q_UINT8 *src1, const Q_UINT8 *src2) +{ + // Arithmetic operands smaller than int are converted to int automatically + return QABS(src2[PIXEL_MASK] - src1[PIXEL_MASK]); +} + +void KisAlphaColorSpace::mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const +{ + if (nColors > 0) { + Q_UINT32 total = 0; + + while(nColors) + { + nColors--; + total += *colors[nColors] * weights[nColors]; + } + *dst = total / 255; + } +} + +QValueVector KisAlphaColorSpace::channels() const +{ + return m_channels; +} + +bool KisAlphaColorSpace::convertPixelsTo(const Q_UINT8 *src, + Q_UINT8 *dst, KisAbstractColorSpace * dstColorSpace, + Q_UINT32 numPixels, + Q_INT32 /*renderingIntent*/) +{ + // No lcms trickery here, we are only a opacity channel + Q_INT32 size = dstColorSpace->pixelSize(); + + Q_UINT32 j = 0; + Q_UINT32 i = 0; + + while ( i < numPixels ) { + + dstColorSpace->fromQColor(Qt::red, OPACITY_OPAQUE - *(src + i), (dst + j)); + + i += 1; + j += size; + + } + return true; + +} + + +//XXX bitblt of ColorSpaceAlpha does not take mask into consideration as this is probably not +// used ever +void KisAlphaColorSpace::bitBlt(Q_UINT8 *dst, + Q_INT32 dststride, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 *srcAlphaMask, + Q_INT32 maskRowStride, + Q_UINT8 opacity, + Q_INT32 rows, + Q_INT32 cols, + const KisCompositeOp& op) +{ + + Q_UINT8 *d; + const Q_UINT8 *s; + Q_INT32 i; + Q_INT32 linesize; + + if (rows <= 0 || cols <= 0) + return; + switch (op.op()) { + case COMPOSITE_COPY: + compositeCopy(dst, dststride, src, srcRowStride, srcAlphaMask, maskRowStride, rows, cols, opacity); + return; + case COMPOSITE_CLEAR: + linesize = sizeof(Q_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; +} + +QString KisAlphaColorSpace::channelValueText(const Q_UINT8 *pixel, Q_UINT32 channelIndex) const +{ + Q_ASSERT(channelIndex < nChannels()); + Q_UINT32 channelPosition = m_channels[channelIndex]->pos(); + + return QString().setNum(pixel[channelPosition]); +} + +QString KisAlphaColorSpace::normalisedChannelValueText(const Q_UINT8 *pixel, Q_UINT32 channelIndex) const +{ + Q_ASSERT(channelIndex < nChannels()); + Q_UINT32 channelPosition = m_channels[channelIndex]->pos(); + + return QString().setNum(static_cast(pixel[channelPosition]) / UINT8_MAX); +} + + +void KisAlphaColorSpace::convolveColors(Q_UINT8** colors, Q_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const +{ + Q_INT32 totalAlpha = 0; + + while (nColors--) + { + Q_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, Q_UINT8_MAX); + } +} diff --git a/krita/kritacolor/colorspaces/kis_alpha_colorspace.h b/krita/kritacolor/colorspaces/kis_alpha_colorspace.h new file mode 100644 index 00000000..a2113cce --- /dev/null +++ b/krita/kritacolor/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 mask is a special color strategy that treats all pixels as + * alpha value with a colour common to the mask. The default color is white. + */ +class KisAlphaColorSpace : public KisU8BaseColorSpace { +public: + KisAlphaColorSpace(KisColorSpaceFactoryRegistry * parent, + KisProfile *p); + virtual ~KisAlphaColorSpace(); + +public: + virtual bool willDegrade(ColorSpaceIndependence) + { + return false; + }; + + virtual void fromQColor(const QColor& c, Q_UINT8 *dst, KisProfile * profile = 0); + virtual void fromQColor(const QColor& c, Q_UINT8 opacity, Q_UINT8 *dst, KisProfile * profile = 0); + + virtual void getAlpha(const Q_UINT8 *pixel, Q_UINT8 *alpha) const; + + virtual void toQColor(const Q_UINT8 *src, QColor *c, KisProfile * profile = 0); + virtual void toQColor(const Q_UINT8 *src, QColor *c, Q_UINT8 *opacity, KisProfile * profile = 0); + + virtual Q_UINT8 difference(const Q_UINT8 *src1, const Q_UINT8 *src2); + virtual void mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const; + + virtual QValueVector channels() const; + virtual Q_UINT32 nChannels() const { return 1; }; + virtual Q_UINT32 nColorChannels() const { return 0; }; + virtual Q_UINT32 pixelSize() const { return 1; }; + + virtual QString channelValueText(const Q_UINT8 *pixel, Q_UINT32 channelIndex) const; + virtual QString normalisedChannelValueText(const Q_UINT8 *pixel, Q_UINT32 channelIndex) const; + + virtual void convolveColors(Q_UINT8** colors, Q_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_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 Q_UINT8 *src, + Q_UINT8 *dst, KisAbstractColorSpace * dstColorSpace, + Q_UINT32 numPixels, + Q_INT32 renderingIntent = INTENT_PERCEPTUAL); + + + + virtual void bitBlt(Q_UINT8 *dst, + Q_INT32 dststride, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 *srcAlphaMask, + Q_INT32 maskRowStride, + Q_UINT8 opacity, + Q_INT32 rows, + Q_INT32 cols, + const KisCompositeOp& op); + + KisCompositeOpList userVisiblecompositeOps() const; + +}; + +#endif // KIS_COLORSPACE_ALPHA_H_ diff --git a/krita/kritacolor/colorspaces/kis_lab_colorspace.cc b/krita/kritacolor/colorspaces/kis_lab_colorspace.cc new file mode 100644 index 00000000..ec370bb3 --- /dev/null +++ b/krita/kritacolor/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 * parent, 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, parent, p) + +{ + m_channels.push_back(new KisChannelInfo(i18n("Lightness"), i18n("L"), CHANNEL_L * sizeof(Q_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(Q_UINT16), QColor(100,100,100))); + m_channels.push_back(new KisChannelInfo(i18n("a*"), i18n("a"), CHANNEL_A * sizeof(Q_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(Q_UINT16), QColor(150,150,150))); + m_channels.push_back(new KisChannelInfo(i18n("b*"), i18n("b"), CHANNEL_B * sizeof(Q_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(Q_UINT16), QColor(200,200,200))); + m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), CHANNEL_ALPHA * sizeof(Q_UINT16), KisChannelInfo::ALPHA, KisChannelInfo::UINT16, sizeof(Q_UINT16))); + + m_alphaPos = CHANNEL_ALPHA * sizeof(Q_UINT16); + + init(); +} + +KisLabColorSpace::~KisLabColorSpace() +{ +} + +Q_UINT8 * KisLabColorSpace::toLabA16(const Q_UINT8 * data, const Q_UINT32 nPixels) const +{ + Q_UINT8 * pixels = new Q_UINT8[nPixels * pixelSize()]; + memcpy( pixels, data, nPixels * pixelSize() ); + return pixels; +} + +Q_UINT8 * KisLabColorSpace::fromLabA16(const Q_UINT8 * labData, const Q_UINT32 nPixels) const +{ + Q_UINT8 * pixels = new Q_UINT8[nPixels * pixelSize()]; + memcpy( pixels, labData, nPixels * pixelSize() ); + return pixels; +} + +Q_UINT8 KisLabColorSpace::difference(const Q_UINT8 *src1, const Q_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 Q_INT8(diff); +} + +void KisLabColorSpace::mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const +{ + Q_UINT32 totalLightness = 0, totalAlpha = 0; + Q_UINT32 totala = 0, totalb = 0; + + while (nColors--) + { + const Pixel *color = reinterpret_cast( *colors ); + Q_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(Q_UINT8 * src, Q_INT32 nPixels) +{ + Q_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(Q_UINT8** colors, Q_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags, + Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const +{ + Q_INT32 totalL = 0, totalA = 0, totalB = 0, totalAlpha = 0; + + while ( nColors -- ) + { + const Pixel * pixel = reinterpret_cast( *colors ); + Q_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, Q_UINT16_MAX); + p->a = CLAMP( ( totalA / factor) + offset, 0, Q_UINT16_MAX); + p->b = CLAMP( ( totalB / factor) + offset, 0, Q_UINT16_MAX); + } + if (channelFlags & KisChannelInfo::FLAG_ALPHA) { + p->alpha = CLAMP((totalAlpha/ factor) + offset, 0, Q_UINT16_MAX); + } + +} + +void KisLabColorSpace::darken(const Q_UINT8 * src, Q_UINT8 * dst, Q_INT32 shade, bool compensate, double compensation, Q_INT32 nPixels) const +{ + // XXX: Is the 255 right for u16 colorspaces? + Q_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; + } +} + + +QValueVector KisLabColorSpace::channels() const +{ + return m_channels; +} + +Q_UINT32 KisLabColorSpace::nChannels() const +{ + return NUM_CHANNELS; +} + +Q_UINT32 KisLabColorSpace::nColorChannels() const +{ + return NUM_COLOR_CHANNELS; +} + +Q_UINT32 KisLabColorSpace::pixelSize() const +{ + return sizeof(Pixel); +} + +void KisLabColorSpace::getSingleChannelPixel(Q_UINT8 *dst, const Q_UINT8 *src, Q_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(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + while (rows > 0) { + const Pixel *src = reinterpret_cast(srcRowStart); + Pixel *dst = reinterpret_cast(dstRowStart); + const Q_UINT8 *mask = maskRowStart; + Q_INT32 columns = numColumns; + + while (columns > 0) { + + Q_UINT16 srcAlpha = src->alpha; + + // apply the alphamask + if (mask != 0) { + if (*mask != OPACITY_OPAQUE) { + srcAlpha = UINT16_MULT(srcAlpha, *mask); + } + mask++; + } + + 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 { + Q_UINT16 dstAlpha = dst->alpha; + + Q_UINT16 srcBlend; + + if (dstAlpha == U16_OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + Q_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(maskRowStart) { + maskRowStart += maskRowStride; + } + } +} + +void KisLabColorSpace::compositeErase(Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowSize, + const Q_UINT8 *srcAlphaMask, + Q_INT32 maskRowStride, + Q_INT32 rows, + Q_INT32 cols, + Q_UINT16 /*opacity*/) +{ + while (rows-- > 0) + { + const Pixel *s = reinterpret_cast(src); + Pixel *d = reinterpret_cast(dst); + const Q_UINT8 *mask = srcAlphaMask; + + for (Q_INT32 i = cols; i > 0; i--, s++, d++) + { + Q_UINT16 srcAlpha = s->alpha; + + // apply the alphamask + if (mask != 0) { + Q_UINT8 U8_mask = *mask; + + if (U8_mask != OPACITY_OPAQUE) { + srcAlpha = UINT16_BLEND(srcAlpha, U16_OPACITY_OPAQUE, UINT8_TO_UINT16(U8_mask)); + } + mask++; + } + d->alpha = UINT16_MULT(srcAlpha, d->alpha); + } + + dst += dstRowSize; + src += srcRowSize; + if(srcAlphaMask) { + srcAlphaMask += maskRowStride; + } + } +} + +void KisLabColorSpace::bitBlt(Q_UINT8 *dst, + Q_INT32 dstRowStride, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 *mask, + Q_INT32 maskRowStride, + Q_UINT8 U8_opacity, + Q_INT32 rows, + Q_INT32 cols, + const KisCompositeOp& op) +{ + Q_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, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DIVIDE: + //compositeDivide(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_LIGHTEN: + //compositeLighten(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_HUE: + //compositeHue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_SATURATION: + //compositeSaturation(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_VALUE: + //compositeValue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COLOR: + //compositeColor(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_OVERLAY: + //compositeOverlay(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ERASE: + compositeErase(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DODGE: + //compositeDodge(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_BURN: + //compositeBurn(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ALPHA_DARKEN: + abstractCompositeAlphaDarken( + dst, dstRowStride, src, srcRowStride, mask, maskRowStride, + 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; +} + +QString KisLabColorSpace::channelValueText(const Q_UINT8 *U8_pixel, Q_UINT32 channelIndex) const +{ + const Pixel *pix = reinterpret_cast(U8_pixel); + Q_ASSERT(channelIndex < nChannels()); + switch(channelIndex) + { + case CHANNEL_L: + return QString().setNum(pix->lightness); + case CHANNEL_A: + return QString().setNum(pix->a); + case CHANNEL_B: + return QString().setNum(pix->b); + case CHANNEL_ALPHA: + return QString().setNum(pix->alpha); + default: + return QString("Error"); + } +} + +QString KisLabColorSpace::normalisedChannelValueText(const Q_UINT8 *U8_pixel, Q_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 QString().setNum(100.0 * static_cast(pix->lightness) / MAX_CHANNEL_L); + case CHANNEL_A: + return QString().setNum(100.0 * ((static_cast(pix->a) - CHANNEL_AB_ZERO_OFFSET) / MAX_CHANNEL_AB)); + case CHANNEL_B: + return QString().setNum(100.0 * ((static_cast(pix->b) - CHANNEL_AB_ZERO_OFFSET) / MAX_CHANNEL_AB)); + case CHANNEL_ALPHA: + return QString().setNum(100.0 * static_cast(pix->alpha) / UINT16_MAX); + default: + return QString("Error"); + } +} + diff --git a/krita/kritacolor/colorspaces/kis_lab_colorspace.h b/krita/kritacolor/colorspaces/kis_lab_colorspace.h new file mode 100644 index 00000000..4108e699 --- /dev/null +++ b/krita/kritacolor/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 * parent, 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 Q_UINT8 * toLabA16(const Q_UINT8 * data, const Q_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 Q_UINT8 * fromLabA16(const Q_UINT8 * labData, const Q_UINT32 nPixels) const; + + + + virtual bool willDegrade(ColorSpaceIndependence independence) + { + if (independence == TO_RGBA8) + return true; + else + return false; + }; + + virtual QValueVector channels() const; + virtual Q_UINT32 nChannels() const; + virtual Q_UINT32 nColorChannels() const; + virtual Q_UINT32 pixelSize() const; + + virtual QString channelValueText(const Q_UINT8 *pixel, Q_UINT32 channelIndex) const; + virtual QString normalisedChannelValueText(const Q_UINT8 *pixel, Q_UINT32 channelIndex) const; + virtual void getSingleChannelPixel(Q_UINT8 *dstPixel, const Q_UINT8 *srcPixel, Q_UINT32 channelIndex); + + virtual Q_UINT8 difference(const Q_UINT8 *src1, const Q_UINT8 *src2); + virtual void mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const; + virtual void invertColor(Q_UINT8 * src, Q_INT32 nPixels); + virtual void convolveColors(Q_UINT8** colors, Q_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const; + + virtual void darken(const Q_UINT8 * src, Q_UINT8 * dst, Q_INT32 shade, bool compensate, double compensation, Q_INT32 nPixels) const; + + virtual KisCompositeOpList userVisiblecompositeOps() const; + +protected: + + virtual void bitBlt(Q_UINT8 *dst, + Q_INT32 dstRowStride, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 *srcAlphaMask, + Q_INT32 maskRowStride, + Q_UINT8 opacity, + Q_INT32 rows, + Q_INT32 cols, + const KisCompositeOp& op); + + void compositeOver(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); +/* + void compositeMultiply(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeDivide(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeScreen(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeOverlay(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeDodge(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeBurn(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeDarken(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeLighten(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeHue(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeSaturation(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeValue(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeColor(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); +*/ + void compositeErase(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + +private: + struct Pixel { + Q_UINT16 lightness; + Q_UINT16 a; + Q_UINT16 b; + Q_UINT16 alpha; + }; + static const Q_UINT16 U16_OPACITY_OPAQUE = UINT16_MAX; + static const Q_UINT16 U16_OPACITY_TRANSPARENT = UINT16_MIN; + + static const Q_UINT32 NUM_CHANNELS = 4; + static const Q_UINT32 NUM_COLOR_CHANNELS = 3; + + static const Q_UINT32 CHANNEL_L = 0; + static const Q_UINT32 CHANNEL_A = 1; + static const Q_UINT32 CHANNEL_B = 2; + static const Q_UINT32 CHANNEL_ALPHA = 3; + + static const Q_UINT32 MAX_CHANNEL_L = 0xff00; + static const Q_UINT32 MAX_CHANNEL_AB = 0xffff; + static const Q_UINT32 CHANNEL_AB_ZERO_OFFSET = 0x8000; + + friend class KisLabColorSpaceTester; +}; + +class KisLabColorSpaceFactory : public KisColorSpaceFactory +{ +public: + /** + * Krita 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 Q_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 * parent, KisProfile *p) { return new KisLabColorSpace(parent, p); }; + + virtual QString defaultProfile() { return "Lab built-in - (lcms internal)"; }; +}; + +#endif // KIS_STRATEGY_COLORSPACE_LAB_H_ diff --git a/krita/kritacolor/colorspaces/kis_xyz_colorspace.cc b/krita/kritacolor/colorspaces/kis_xyz_colorspace.cc new file mode 100644 index 00000000..3d14ea18 --- /dev/null +++ b/krita/kritacolor/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) // ((Q_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 * parent, + KisProfile *p) : + KisU16BaseColorSpace(KisID("XYZA", i18n("XYZ/Alpha")), (COLORSPACE_SH(PT_XYZ)|CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)), icSigCmykData, parent, 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(Q_UINT16); + + init(); +} + + +KisXyzColorSpace::~KisXyzColorSpace() +{ +} + + +QValueVector KisXyzColorSpace::channels() const +{ + return m_channels; +} + +Q_UINT32 KisXyzColorSpace::nChannels() const +{ + return xyz::MAX_CHANNEL_XYZA; +} + +Q_UINT32 KisXyzColorSpace::nColorChannels() const +{ + return xyz::MAX_CHANNEL_XYZ; +} + +Q_UINT32 KisXyzColorSpace::pixelSize() const +{ + return xyz::MAX_CHANNEL_XYZA * sizeof(Q_UINT16); +} + +KisColorAdjustment * KisXyzColorSpace::createBrightnessContrastAdjustment(Q_UINT16 *transferValues) +{ + return 0; +} + +void KisXyzColorSpace::applyAdjustment(const Q_UINT8 *src, Q_UINT8 *dst, KisColorAdjustment *, Q_INT32 nPixels) +{ +} + +void KisXyzColorSpace::invertColor(Q_UINT8 * src, Q_INT32 nPixels) +{ + Q_INT32 pSize = pixelSize(); + + while (nPixels--) + { + Q_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 Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const +{ +} + +void KisXyzColorSpace::convolveColors(Q_UINT8** colors, Q_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nPixels) const +{ +} + +void KisXyzColorSpace::darken(const Q_UINT8 * src, Q_UINT8 * dst, Q_INT32 shade, bool compensate, double compensation, Q_INT32 nPixels) const +{ +} + +Q_UINT8 KisXyzColorSpace::intensity8(const Q_UINT8 * src) const +{ + return 0; +} + +void KisXyzColorSpace::compositeOver(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + while (rows > 0) { + + const Q_UINT16 *src = reinterpret_cast(srcRowStart); + Q_UINT16 *dst = reinterpret_cast(dstRowStart); + const Q_UINT8 *mask = maskRowStart; + Q_INT32 columns = numColumns; + + while (columns > 0) { + + Q_UINT16 srcAlpha = src[PIXEL_ALPHA]; + + // apply the alphamask + if (mask != 0) { + Q_UINT8 U8_mask = *mask; + + if (U8_mask != OPACITY_OPAQUE) { + srcAlpha = UINT16_MULT(srcAlpha, UINT8_TO_UINT16(U8_mask)); + } + mask++; + } + + 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(Q_UINT16)); + } else { + Q_UINT16 dstAlpha = dst[PIXEL_ALPHA]; + + Q_UINT16 srcBlend; + + if (dstAlpha == U16_OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + Q_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(Q_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(maskRowStart) { + maskRowStart += maskRowStride; + } + } +} + +#define COMMON_COMPOSITE_OP_PROLOG() \ + while (rows > 0) { \ + \ + const Q_UINT16 *src = reinterpret_cast(srcRowStart); \ + Q_UINT16 *dst = reinterpret_cast(dstRowStart); \ + Q_INT32 columns = numColumns; \ + const Q_UINT8 *mask = maskRowStart; \ + \ + while (columns > 0) { \ + \ + Q_UINT16 srcAlpha = src[PIXEL_ALPHA]; \ + Q_UINT16 dstAlpha = dst[PIXEL_ALPHA]; \ + \ + srcAlpha = QMIN(srcAlpha, dstAlpha); \ + \ + if (mask != 0) { \ + Q_UINT8 U8_mask = *mask; \ + \ + if (U8_mask != OPACITY_OPAQUE) { \ + srcAlpha = UINT16_MULT(srcAlpha, UINT8_TO_UINT16(U8_mask)); \ + } \ + mask++; \ + } \ + \ + if (srcAlpha != U16_OPACITY_TRANSPARENT) { \ + \ + if (opacity != U16_OPACITY_OPAQUE) { \ + srcAlpha = UINT16_MULT(srcAlpha, opacity); \ + } \ + \ + Q_UINT16 srcBlend; \ + \ + if (dstAlpha == U16_OPACITY_OPAQUE) { \ + srcBlend = srcAlpha; \ + } else { \ + Q_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(maskRowStart) { \ + maskRowStart += maskRowStride; \ + } \ + } + +void KisXyzColorSpace::compositeMultiply(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + + for (int channel = 0; channel < xyz::MAX_CHANNEL_XYZ; channel++) { + Q_UINT16 srcColor = src[channel]; + Q_UINT16 dstColor = dst[channel]; + + srcColor = UINT16_MULT(srcColor, dstColor); + + dst[channel] = UINT16_BLEND(srcColor, dstColor, srcBlend); + + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisXyzColorSpace::compositeDivide(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < xyz::MAX_CHANNEL_XYZ; channel++) { + + Q_UINT16 srcColor = src[channel]; + Q_UINT16 dstColor = dst[channel]; + + srcColor = QMIN((dstColor * (UINT16_MAX + 1u) + (srcColor / 2u)) / (1u + srcColor), UINT16_MAX); + + Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisXyzColorSpace::compositeScreen(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < xyz::MAX_CHANNEL_XYZ; channel++) { + + Q_UINT16 srcColor = src[channel]; + Q_UINT16 dstColor = dst[channel]; + + srcColor = UINT16_MAX - UINT16_MULT(UINT16_MAX - dstColor, UINT16_MAX - srcColor); + + Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisXyzColorSpace::compositeOverlay(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < xyz::MAX_CHANNEL_XYZ; channel++) { + + Q_UINT16 srcColor = src[channel]; + Q_UINT16 dstColor = dst[channel]; + + srcColor = UINT16_MULT(dstColor, dstColor + 2u * UINT16_MULT(srcColor, UINT16_MAX - dstColor)); + + Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisXyzColorSpace::compositeDodge(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < xyz::MAX_CHANNEL_XYZ; channel++) { + + Q_UINT16 srcColor = src[channel]; + Q_UINT16 dstColor = dst[channel]; + + srcColor = QMIN((dstColor * (UINT16_MAX + 1u)) / (UINT16_MAX + 1u - srcColor), UINT16_MAX); + + Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisXyzColorSpace::compositeBurn(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < xyz::MAX_CHANNEL_XYZ; channel++) { + + Q_UINT16 srcColor = src[channel]; + Q_UINT16 dstColor = dst[channel]; + + srcColor = QMIN(((UINT16_MAX - dstColor) * (UINT16_MAX + 1u)) / (srcColor + 1u), UINT16_MAX); + srcColor = CLAMP(UINT16_MAX - srcColor, 0u, UINT16_MAX); + + Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisXyzColorSpace::compositeDarken(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < xyz::MAX_CHANNEL_XYZ; channel++) { + + Q_UINT16 srcColor = src[channel]; + Q_UINT16 dstColor = dst[channel]; + + srcColor = QMIN(srcColor, dstColor); + + Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisXyzColorSpace::compositeLighten(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < xyz::MAX_CHANNEL_XYZ; channel++) { + + Q_UINT16 srcColor = src[channel]; + Q_UINT16 dstColor = dst[channel]; + + srcColor = QMAX(srcColor, dstColor); + + Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + + + +void KisXyzColorSpace::compositeErase(Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowSize, + const Q_UINT8 *srcAlphaMask, + Q_INT32 maskRowStride, + Q_INT32 rows, + Q_INT32 cols, + Q_UINT16 /*opacity*/) +{ + while (rows-- > 0) + { + const Pixel *s = reinterpret_cast(src); + Pixel *d = reinterpret_cast(dst); + const Q_UINT8 *mask = srcAlphaMask; + + for (Q_INT32 i = cols; i > 0; i--, s++, d++) + { + Q_UINT16 srcAlpha = s -> alpha; + + // apply the alphamask + if (mask != 0) { + Q_UINT8 U8_mask = *mask; + + if (U8_mask != OPACITY_OPAQUE) { + srcAlpha = UINT16_BLEND(srcAlpha, U16_OPACITY_OPAQUE, UINT8_TO_UINT16(U8_mask)); + } + mask++; + } + d -> alpha = UINT16_MULT(srcAlpha, d -> alpha); + } + + dst += dstRowSize; + src += srcRowSize; + if(srcAlphaMask) { + srcAlphaMask += maskRowStride; + } + } +} + +void KisXyzColorSpace::bitBlt(Q_UINT8 *dst, + Q_INT32 dstRowStride, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 *mask, + Q_INT32 maskRowStride, + Q_UINT8 U8_opacity, + Q_INT32 rows, + Q_INT32 cols, + const KisCompositeOp& op) +{ + Q_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, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DIVIDE: + compositeDivide(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_LIGHTEN: + compositeLighten(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_HUE: + //compositeHue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_SATURATION: + //compositeSaturation(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_VALUE: + //compositeValue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COLOR: + //compositeColor(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_OVERLAY: + compositeOverlay(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ERASE: + compositeErase(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DODGE: + compositeDodge(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_BURN: + compositeBurn(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ALPHA_DARKEN: + abstractCompositeAlphaDarken( + dst, dstRowStride, src, srcRowStride, mask, maskRowStride, + 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/krita/kritacolor/colorspaces/kis_xyz_colorspace.h b/krita/kritacolor/colorspaces/kis_xyz_colorspace.h new file mode 100644 index 00000000..86af9178 --- /dev/null +++ b/krita/kritacolor/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 Q_INT32 MAX_CHANNEL_XYZ = 3; + const Q_INT32 MAX_CHANNEL_XYZA = 4; +} + + + +class KisXyzColorSpace : public KisU16BaseColorSpace { + +public: + + struct Pixel { + Q_UINT16 X; + Q_UINT16 Y; + Q_UINT16 Z; + Q_UINT16 alpha; + }; + +public: + KisXyzColorSpace(KisColorSpaceFactoryRegistry * parent, + KisProfile *p); + virtual ~KisXyzColorSpace(); + + virtual bool willDegrade(ColorSpaceIndependence independence) + { + if (independence == TO_RGBA8) + return true; + else + return false; + }; +public: + // Pixel manipulation + virtual KisColorAdjustment *createBrightnessContrastAdjustment(Q_UINT16 *transferValues); + virtual void applyAdjustment(const Q_UINT8 *src, Q_UINT8 *dst, KisColorAdjustment *, Q_INT32 nPixels); + virtual void invertColor(Q_UINT8 * src, Q_INT32 nPixels); + virtual void mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const; + virtual void convolveColors(Q_UINT8** colors, Q_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nPixels) const; + virtual void darken(const Q_UINT8 * src, Q_UINT8 * dst, Q_INT32 shade, bool compensate, double compensation, Q_INT32 nPixels) const; + virtual Q_UINT8 intensity8(const Q_UINT8 * src) const; + + // Information about the colorstrategy + virtual QValueVector channels() const; + virtual Q_UINT32 nChannels() const; + virtual Q_UINT32 nColorChannels() const; + virtual Q_UINT32 pixelSize() const; + + + // Composition + + virtual void bitBlt(Q_UINT8 *dst, + Q_INT32 dststride, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 *srcAlphaMask, + Q_INT32 maskRowStride, + Q_UINT8 opacity, + Q_INT32 rows, + Q_INT32 cols, + const KisCompositeOp& op); + + KisCompositeOpList userVisiblecompositeOps() const; + +protected: + void compositeOver(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeMultiply(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeDivide(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeScreen(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeOverlay(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeDodge(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeBurn(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeDarken(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeLighten(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + void compositeErase(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity); + +private: + + static const Q_UINT8 PIXEL_X = 0; + static const Q_UINT8 PIXEL_Y = 1; + static const Q_UINT8 PIXEL_Z = 2; + static const Q_UINT8 PIXEL_ALPHA = 3; + + Q_UINT8 * m_qcolordata; // A small buffer for conversion from and to qcolor. + +}; + +#endif // KIS__COLORSPACE_XYZ_H_ diff --git a/krita/kritacolor/kis_abstract_colorspace.cc b/krita/kritacolor/kis_abstract_colorspace.cc new file mode 100644 index 00000000..0a6ad8e9 --- /dev/null +++ b/krita/kritacolor/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 * parent, + KisProfile *p) + : m_parent( parent ) + , 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 QColor conversion + m_qcolordata = new Q_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::fromQColor(const QColor& color, Q_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::fromQColor(const QColor& color, Q_UINT8 opacity, Q_UINT8 *dst, KisProfile * profile) +{ + fromQColor(color, dst, profile); + setAlpha(dst, opacity, 1); +} + +void KisAbstractColorSpace::toQColor(const Q_UINT8 *src, QColor *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::toQColor(const Q_UINT8 *src, QColor *c, Q_UINT8 *opacity, KisProfile * profile) +{ + toQColor(src, c, profile); + *opacity = getAlpha(src); +} + +void KisAbstractColorSpace::toLabA16(const Q_UINT8 * src, Q_UINT8 * dst, const Q_UINT32 nPixels) const +{ + if ( m_defaultToLab == 0 ) return; + + cmsDoTransform( m_defaultToLab, const_cast( src ), dst, nPixels ); +} + +void KisAbstractColorSpace::fromLabA16(const Q_UINT8 * src, Q_UINT8 * dst, const Q_UINT32 nPixels) const +{ + if ( m_defaultFromLab == 0 ) return; + + cmsDoTransform( m_defaultFromLab, const_cast( src ), dst, nPixels ); +} + + +void KisAbstractColorSpace::getSingleChannelPixel(Q_UINT8 *dstPixel, const Q_UINT8 *srcPixel, Q_UINT32 channelIndex) +{ + if (channelIndex < m_channels.count()) { + + fromQColor(Qt::black, OPACITY_TRANSPARENT, dstPixel); + + const KisChannelInfo *channelInfo = m_channels[channelIndex]; + memcpy(dstPixel + channelInfo->pos(), srcPixel + channelInfo->pos(), channelInfo->size()); + } +} + +bool KisAbstractColorSpace::convertPixelsTo(const Q_UINT8 * src, + Q_UINT8 * dst, + KisColorSpace * dstColorSpace, + Q_UINT32 numPixels, + Q_INT32 renderingIntent) +{ + if (dstColorSpace->colorSpaceType() == colorSpaceType() + && dstColorSpace->getProfile() == getProfile()) + { + if (src!= dst) + memcpy (dst, src, numPixels * pixelSize()); + + return true; + } + + cmsHTRANSFORM tf = 0; + + Q_INT32 srcPixelSize = pixelSize(); + Q_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.contains(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) { + Q_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) { + QColor color; + Q_UINT8 opacity; + + toQColor(src, &color, &opacity); + dstColorSpace->fromQColor(color, opacity, dst); + + src += srcPixelSize; + dst += dstPixelSize; + numPixels--; + } + + return true; +} + + +KisColorAdjustment *KisAbstractColorSpace::createBrightnessContrastAdjustment(Q_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) "(krita internal)"); + cmsAddTag(adj->profiles[1], icSigProfileDescriptionTag, (LPVOID) "krita 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(Q_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 Q_UINT8 *src, Q_UINT8 *dst, KisColorAdjustment *adjustment, Q_INT32 nPixels) +{ + KisColorAdjustmentImpl * adj = dynamic_cast(adjustment); + if (adj) + cmsDoTransform(adj->transform, const_cast(src), dst, nPixels); +} + + +void KisAbstractColorSpace::invertColor(Q_UINT8 * src, Q_INT32 nPixels) +{ + QColor c; + Q_UINT8 opacity; + Q_UINT32 psize = pixelSize(); + + while (nPixels--) + { + toQColor(src, &c, &opacity); + c.setRgb(Q_UINT8_MAX - c.red(), Q_UINT8_MAX - c.green(), Q_UINT8_MAX - c.blue()); + fromQColor( c, opacity, src); + + src += psize; + } +} + +Q_UINT8 KisAbstractColorSpace::difference(const Q_UINT8* src1, const Q_UINT8* src2) +{ + if (m_defaultToLab) { + + Q_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 Q_INT8(diff); + } + else { + QColor c1; + Q_UINT8 opacity1; + toQColor(src1, &c1, &opacity1); + + QColor c2; + Q_UINT8 opacity2; + toQColor(src2, &c2, &opacity2); + + Q_UINT8 red = abs(c1.red() - c2.red()); + Q_UINT8 green = abs(c1.green() - c2.green()); + Q_UINT8 blue = abs(c1.blue() - c2.blue()); + return QMAX(red, QMAX(green, blue)); + } +} + +void KisAbstractColorSpace::mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const +{ + Q_UINT32 totalRed = 0, totalGreen = 0, totalBlue = 0, newAlpha = 0; + + QColor c; + Q_UINT8 opacity; + + while (nColors--) + { + // Ugly hack to get around the current constness mess of the colour strategy... + const_cast(this)->toQColor(*colors, &c, &opacity); + + Q_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; + + Q_UINT32 dstRed = ((totalRed >> 8) + totalRed) >> 8; + Q_ASSERT(dstRed <= 255); + + totalGreen += 0x80; + Q_UINT32 dstGreen = ((totalGreen >> 8) + totalGreen) >> 8; + Q_ASSERT(dstGreen <= 255); + + totalBlue += 0x80; + Q_UINT32 dstBlue = ((totalBlue >> 8) + totalBlue) >> 8; + Q_ASSERT(dstBlue <= 255); + + const_cast(this)->fromQColor(QColor(dstRed, dstGreen, dstBlue), newAlpha, dst); +} + +void KisAbstractColorSpace::convolveColors(Q_UINT8** colors, Q_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags, + Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const +{ + Q_INT32 totalRed = 0, totalGreen = 0, totalBlue = 0, totalAlpha = 0; + + QColor dstColor; + Q_UINT8 dstOpacity; + + const_cast(this)->toQColor(dst, &dstColor, &dstOpacity); + + while (nColors--) + { + Q_INT32 weight = *kernelValues; + + if (weight != 0) { + QColor c; + Q_UINT8 opacity; + const_cast(this)->toQColor( *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)->fromQColor(QColor(CLAMP((totalRed / factor) + offset, 0, Q_UINT8_MAX), + CLAMP((totalGreen / factor) + offset, 0, Q_UINT8_MAX), + CLAMP((totalBlue / factor) + offset, 0, Q_UINT8_MAX)), + dstOpacity, + dst); + } + if (channelFlags & KisChannelInfo::FLAG_ALPHA) { + const_cast(this)->fromQColor(dstColor, CLAMP((totalAlpha/ factor) + offset, 0, Q_UINT8_MAX), dst); + } + +} + +void KisAbstractColorSpace::darken(const Q_UINT8 * src, Q_UINT8 * dst, Q_INT32 shade, bool compensate, double compensation, Q_INT32 nPixels) const +{ + if (m_defaultToLab) { + Q_UINT16 * labcache = new Q_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 ) { + Q_UINT8 alpha = getAlpha( src ); + setAlpha( dst, alpha, 1 ); + } + delete [] labcache; + } + else { + + QColor c; + Q_INT32 psize = pixelSize(); + + for (int i = 0; i < nPixels; ++i) { + + const_cast(this)->toQColor(src + (i * psize), &c); + Q_INT32 r, g, b; + + if (compensate) { + r = static_cast( QMIN(255, (c.red() * shade) / (compensation * 255))); + g = static_cast( QMIN(255, (c.green() * shade) / (compensation * 255))); + b = static_cast( QMIN(255, (c.blue() * shade) / (compensation * 255))); + } + else { + r = static_cast( QMIN(255, (c.red() * shade / 255))); + g = static_cast( QMIN(255, (c.green() * shade / 255))); + b = static_cast( QMIN(255, (c.blue() * shade / 255))); + } + c.setRgb(r, g, b); + + const_cast(this)->fromQColor( c, dst + (i * psize)); + } + } +} + +Q_UINT8 KisAbstractColorSpace::intensity8(const Q_UINT8 * src) const +{ + QColor c; + Q_UINT8 opacity; + const_cast(this)->toQColor(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(Q_UINT8 *dst, + Q_INT32 dststride, + KisColorSpace * srcSpace, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 *srcAlphaMask, + Q_INT32 maskRowStride, + Q_UINT8 opacity, + Q_INT32 rows, + Q_INT32 cols, + const KisCompositeOp& op) +{ + if (rows <= 0 || cols <= 0) + return; + + if (this != srcSpace) { + Q_UINT32 len = pixelSize() * rows * cols; + + // If our conversion cache is too small, extend it. + if (!m_conversionCache.resize( len, QGArray::SpeedOptim )) { + kdWarning() << "Could not allocate enough memory for the conversion!\n"; + // XXX: We should do a slow, pixel by pixel bitblt here... + abort(); + } + + for (Q_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, + maskRowStride, + opacity, + rows, + cols, + op); + + } + else { + bitBlt(dst, + dststride, + src, + srcRowStride, + srcAlphaMask, + maskRowStride, + opacity, + rows, + cols, + op); + } +} + +QImage KisAbstractColorSpace::convertToQImage(const Q_UINT8 *data, Q_INT32 width, Q_INT32 height, + KisProfile *dstProfile, + Q_INT32 renderingIntent, float /*exposure*/) + +{ + QImage img = QImage(width, height, 32, 0, QImage::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, + Q_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(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 * /*maskRowStart*/, Q_INT32 /*maskRowStride*/, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity) +{ + Q_UINT8 *dst = dstRowStart; + const Q_UINT8 *src = srcRowStart; + Q_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/krita/kritacolor/kis_abstract_colorspace.h b/krita/kritacolor/kis_abstract_colorspace.h new file mode 100644 index 00000000..b201986a --- /dev/null +++ b/krita/kritacolor/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 QPainter; +class KisPixelRO; +class KisColorSpaceFactoryRegistry; + + +/** + * A colorspace strategy is the definition of a certain color model + * in Krita. + */ +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 parent the registry that owns this instance + * @param profile the profile this colorspace uses for transforms + */ + KisAbstractColorSpace(const KisID & id, + DWORD cmType, + icColorSpaceSignature colorSpaceSignature, + KisColorSpaceFactoryRegistry * parent, + 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 QValueVector channels() const = 0; + + virtual Q_UINT32 nChannels() const = 0; + + virtual Q_UINT32 nColorChannels() const = 0; + + virtual Q_UINT32 nSubstanceChannels() const { return 0; }; + + virtual Q_UINT32 pixelSize() const = 0; + + virtual QString channelValueText(const Q_UINT8 *pixel, Q_UINT32 channelIndex) const = 0; + + virtual QString normalisedChannelValueText(const Q_UINT8 *pixel, Q_UINT32 channelIndex) const = 0; + + virtual Q_UINT8 scaleToU8(const Q_UINT8 * srcPixel, Q_INT32 channelPos) = 0; + + virtual Q_UINT16 scaleToU16(const Q_UINT8 * srcPixel, Q_INT32 channelPos) = 0; + + virtual void getSingleChannelPixel(Q_UINT8 *dstPixel, const Q_UINT8 *srcPixel, Q_UINT32 channelIndex); + + //========== Identification ===============================================// + + virtual KisID id() const { return m_id; } + + void setColorSpaceType(Q_UINT32 type) { m_cmType = type; } + Q_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 fromQColor(const QColor& c, Q_UINT8 *dst, KisProfile * profile = 0); + virtual void fromQColor(const QColor& c, Q_UINT8 opacity, Q_UINT8 *dst, KisProfile * profile = 0); + + virtual void toQColor(const Q_UINT8 *src, QColor *c, KisProfile * profile = 0); + virtual void toQColor(const Q_UINT8 *src, QColor *c, Q_UINT8 *opacity, KisProfile * profile = 0); + + + virtual void toLabA16(const Q_UINT8 * src, Q_UINT8 * dst, const Q_UINT32 nPixels) const; + virtual void fromLabA16(const Q_UINT8 * src, Q_UINT8 * dst, const Q_UINT32 nPixels) const; + + virtual QImage convertToQImage(const Q_UINT8 *data, Q_INT32 width, Q_INT32 height, + KisProfile * dstProfile, + Q_INT32 renderingIntent = INTENT_PERCEPTUAL, + float exposure = 0.0f); + + virtual bool convertPixelsTo(const Q_UINT8 * src, + Q_UINT8 * dst, KisColorSpace * dstColorSpace, + Q_UINT32 numPixels, + Q_INT32 renderingIntent = INTENT_PERCEPTUAL); + +//============================== Manipulation fucntions ==========================// + + +// +// The manipulation functions have default implementations that _convert_ the pixel +// to a QColor and back. Reimplement these methods in your color strategy! +// + virtual KisColorAdjustment *createBrightnessContrastAdjustment(Q_UINT16 *transferValues); + + virtual KisColorAdjustment *createDesaturateAdjustment(); + + virtual KisColorAdjustment *createPerChannelAdjustment(Q_UINT16 **transferValues); + + virtual void applyAdjustment(const Q_UINT8 *src, Q_UINT8 *dst, KisColorAdjustment *, Q_INT32 nPixels); + + virtual void invertColor(Q_UINT8 * src, Q_INT32 nPixels); + + virtual Q_UINT8 difference(const Q_UINT8* src1, const Q_UINT8* src2); + + virtual void mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const; + + virtual void convolveColors(Q_UINT8** colors, Q_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nPixels) const; + + virtual void darken(const Q_UINT8 * src, Q_UINT8 * dst, Q_INT32 shade, bool compensate, double compensation, Q_INT32 nPixels) const; + + virtual Q_UINT8 intensity8(const Q_UINT8 * src) const; + + virtual KisID mathToolboxID() const; + + virtual void bitBlt(Q_UINT8 *dst, + Q_INT32 dststride, + KisColorSpace * srcSpace, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 *srcAlphaMask, + Q_INT32 maskRowStride, + Q_UINT8 opacity, + Q_INT32 rows, + Q_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(Q_UINT8 *dst, + Q_INT32 dstRowSize, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 *srcAlphaMask, + Q_INT32 maskRowStride, + Q_UINT8 opacity, + Q_INT32 rows, + Q_INT32 cols, + const KisCompositeOp& op) = 0; + + virtual cmsHTRANSFORM createTransform(KisColorSpace * dstColorSpace, + KisProfile * srcProfile, + KisProfile * dstProfile, + Q_INT32 renderingIntent); + + virtual void compositeCopy(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity); + + + // So I don't need to re-implement it everywhere. + template + void abstractCompositeAlphaDarken(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, + const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, + const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, + Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity, + NativeMult nativeMult, Uint8ToNative uint8ToNative, + NativeOpacityTest nativeOpacityTest) { + while (rows > 0) { + + const ColorType *src = reinterpret_cast(srcRowStart); + ColorType *dst = reinterpret_cast(dstRowStart); + const Q_UINT8 *mask = maskRowStart; + Q_INT32 columns = numColumns; + + while (columns > 0) { + + ColorType srcAlpha = src[AlphaPos]; + ColorType dstAlpha = dst[AlphaPos]; + + // apply the alphamask + if(mask != 0) + { + if(*mask != OPACITY_OPAQUE) + srcAlpha = nativeMult(srcAlpha, uint8ToNative(*mask)); + mask++; + } + + 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(maskRowStart) + maskRowStart += maskRowStride; + } + } + +protected: + + QStringList m_profileFilenames; + Q_UINT8 * m_qcolordata; // A small buffer for conversion from and to qcolor. + Q_INT32 m_alphaPos; // The position in _bytes_ of the alpha channel + Q_INT32 m_alphaSize; // The width in _bytes_ of the alpha channel + + QValueVector 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 QMap TransformMap; + TransformMap m_transforms; // Cache for existing transforms + + KisAbstractColorSpace(const KisAbstractColorSpace&); + KisAbstractColorSpace& operator=(const KisAbstractColorSpace&); + + QMemArray m_conversionCache; // XXX: This will be a bad problem when we have threading. +}; + +#endif // KIS_STRATEGY_COLORSPACE_H_ diff --git a/krita/kritacolor/kis_basic_histogram_producers.cc b/krita/kritacolor/kis_basic_histogram_producers.cc new file mode 100644 index 00000000..2b9994d3 --- /dev/null +++ b/krita/kritacolor/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 + QValueVector 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) +{ +} + +QString KisBasicU8HistogramProducer::positionToString(double pos) const { + return QString("%1").arg(static_cast(pos * UINT8_MAX)); +} + +void KisBasicU8HistogramProducer::addRegionToBin(Q_UINT8 * pixels, Q_UINT8 * selectionMask, Q_UINT32 nPixels, KisColorSpace *cs) +{ + if (!pixels) return; + if (!cs) return; + if (nPixels == 0) return; + + Q_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) +{ +} + +QString KisBasicU16HistogramProducer::positionToString(double pos) const +{ + return QString("%1").arg(static_cast(pos * UINT8_MAX)); +} + +double KisBasicU16HistogramProducer::maximalZoom() const +{ + return 1.0 / 255.0; +} + +void KisBasicU16HistogramProducer::addRegionToBin(Q_UINT8 * pixels, Q_UINT8 * selectionMask, Q_UINT32 nPixels, KisColorSpace *cs) +{ + // The view + Q_UINT16 from = static_cast(m_from * UINT16_MAX); + Q_UINT16 width = static_cast(m_width * UINT16_MAX + 0.5); // We include the end + Q_UINT16 to = from + width; + double factor = 255.0 / width; + + Q_INT32 pSize = cs->pixelSize(); + + if ( selectionMask ) { + Q_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++) { + Q_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) { + Q_UINT16* pixel = reinterpret_cast(pixels); + + if ( ! (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) { + for (int i = 0; i < m_channels; i++) { + Q_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) +{ +} + +QString KisBasicF32HistogramProducer::positionToString(double pos) const { + return QString("%1").arg(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(Q_UINT8 * pixels, Q_UINT8 * selectionMask, Q_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; + + Q_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) { +} + +QString KisBasicF16HalfHistogramProducer::positionToString(double pos) const { + return QString("%1").arg(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(Q_UINT8 * pixels, Q_UINT8 * selectionMask, Q_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; + + Q_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, QColor(255,0,0))); + m_channelsList.append(new KisChannelInfo(i18n("G"), i18n("G"), 1, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, QColor(0,255,0))); + m_channelsList.append(new KisChannelInfo(i18n("B"), i18n("B"), 2, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, QColor(0,0,255))); +} + +QValueVector KisGenericRGBHistogramProducer::channels() { + return m_channelsList; +} + +QString KisGenericRGBHistogramProducer::positionToString(double pos) const { + return QString("%1").arg(static_cast(pos * UINT8_MAX)); +} + +double KisGenericRGBHistogramProducer::maximalZoom() const { + return 1.0; +} + + +void KisGenericRGBHistogramProducer::addRegionToBin(Q_UINT8 * pixels, Q_UINT8 * selectionMask, Q_UINT32 nPixels, KisColorSpace *cs) +{ + for (int i = 0; i < m_channels; i++) { + m_outRight.at(i) = 0; + m_outLeft.at(i) = 0; + } + + QColor c; + Q_INT32 pSize = cs->pixelSize(); + if (selectionMask) { + while (nPixels > 0) { + if ( !((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) { + cs->toQColor(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->toQColor(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]; +} + +QValueVector KisGenericLabHistogramProducer::channels() { + return m_channelsList; +} + +QString KisGenericLabHistogramProducer::positionToString(double pos) const { + return QString("%1").arg(static_cast(pos * UINT16_MAX)); +} + +double KisGenericLabHistogramProducer::maximalZoom() const { + return 1.0; +} + + +void KisGenericLabHistogramProducer::addRegionToBin(Q_UINT8 * pixels, Q_UINT8 * selectionMask, Q_UINT32 nPixels, KisColorSpace *cs) +{ + for (int i = 0; i < m_channels; i++) { + m_outRight.at(i) = 0; + m_outLeft.at(i) = 0; + } + + Q_UINT8 dst[8]; + Q_INT32 pSize = cs->pixelSize(); + + if (selectionMask) { + while (nPixels > 0) { + if ( !((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) { +/* + cs->toQColor(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/krita/kritacolor/kis_basic_histogram_producers.h b/krita/kritacolor/kis_basic_histogram_producers.h new file mode 100644 index 00000000..498c7be4 --- /dev/null +++ b/krita/kritacolor/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 QValueVector channels() { return m_colorSpace->channels(); } + virtual Q_INT32 numberOfBins() { return m_nrOfBins; } + virtual double viewFrom() const { return m_from; } + virtual double viewWidth() const { return m_width; } + + virtual Q_INT32 count() { return m_count; } + + virtual Q_INT32 getBinAt(int channel, int position) + { return m_bins.at(externalToInternal(channel)).at(position); } + + virtual Q_INT32 outOfViewLeft(int channel) + { return m_outLeft.at(externalToInternal(channel)); } + + virtual Q_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 layout 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 QValueVector vBins; + QValueVector m_bins; + vBins m_outLeft, m_outRight; + double m_from, m_width; + Q_INT32 m_count; + int m_channels, m_nrOfBins; + KisColorSpace *m_colorSpace; + KisID m_id; + QValueVector m_external; +}; + +class KisBasicU8HistogramProducer : public KisBasicHistogramProducer { +public: + KisBasicU8HistogramProducer(const KisID& id, KisColorSpace *colorSpace); + virtual void addRegionToBin(Q_UINT8 * pixels, Q_UINT8 * selectionMask, Q_UINT32 nPixels, KisColorSpace *colorSpace); + virtual QString 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(Q_UINT8 * pixels, Q_UINT8 * selectionMask, Q_UINT32 nPixels, KisColorSpace *colorSpace); + virtual QString positionToString(double pos) const; + virtual double maximalZoom() const; +}; + +class KisBasicF32HistogramProducer : public KisBasicHistogramProducer { +public: + KisBasicF32HistogramProducer(const KisID& id, KisColorSpace *colorSpace); + virtual void addRegionToBin(Q_UINT8 * pixels, Q_UINT8 * selectionMask, Q_UINT32 nPixels, KisColorSpace *colorSpace); + virtual QString 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(Q_UINT8 * pixels, Q_UINT8 * selectionMask, Q_UINT32 nPixels, KisColorSpace *colorSpace); + virtual QString 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 toQColor, 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(Q_UINT8 * pixels, Q_UINT8 * selectionMask, Q_UINT32 nPixels, KisColorSpace *colorSpace); + virtual QString positionToString(double pos) const; + virtual double maximalZoom() const; + virtual QValueVector channels(); +protected: + QValueVector 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(Q_UINT8 * pixels, Q_UINT8 * selectionMask, Q_UINT32 nPixels, KisColorSpace *colorSpace); + virtual QString positionToString(double pos) const; + virtual double maximalZoom() const; + virtual QValueVector channels(); + protected: + QValueVector 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/krita/kritacolor/kis_channelinfo.h b/krita/kritacolor/kis_channelinfo.h new file mode 100644 index 00000000..f37d8900 --- /dev/null +++ b/krita/kritacolor/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 "qstring.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 QString & name, const QString & abbrev, Q_INT32 npos, enumChannelType channelType, enumChannelValueType channelValueType, Q_INT32 size = 1, QColor color = QColor(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 QString name() const { return m_name; }; + + /** + * Return the single-letter abbreviation for this channel + */ + inline QString abbrev() const { return m_abbrev; }; + /** + * returns the position of the first byte of the channel in the pixel + */ + inline Q_INT32 pos() const { return m_pos; }; + + /** + * returns the number of bytes this channel takes + */ + inline Q_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 QColor color() const { return m_color; } + +private: + + QString m_name; + QString m_abbrev; + Q_INT32 m_pos; + enumChannelType m_channelType; + enumChannelValueType m_channelValueType; + Q_INT32 m_size; + QColor m_color; + +}; + +#endif // KIS_CHANNELINFO_H_ diff --git a/krita/kritacolor/kis_color.cc b/krita/kritacolor/kis_color.cc new file mode 100644 index 00000000..eb845c27 --- /dev/null +++ b/krita/kritacolor/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 QColor & color, KisColorSpace * colorSpace) + : m_colorSpace(colorSpace) +{ + Q_ASSERT(color.isValid()); + Q_ASSERT(colorSpace); + + m_data = new Q_UINT8[colorSpace->pixelSize()]; + memset(m_data, 0, m_colorSpace->pixelSize()); + + m_colorSpace->fromQColor(color, OPACITY_OPAQUE, m_data); +} + + +KisColor::KisColor(const QColor & color, Q_UINT8 alpha, KisColorSpace * colorSpace) + : m_colorSpace(colorSpace) +{ + Q_ASSERT(color.isValid()); + Q_ASSERT(colorSpace); + m_data = new Q_UINT8[colorSpace->pixelSize()]; + memset(m_data, 0, m_colorSpace->pixelSize()); + + m_colorSpace->fromQColor(color, alpha, m_data); +} + +KisColor::KisColor(const Q_UINT8 * data, KisColorSpace * colorSpace) + : m_colorSpace(colorSpace) +{ + + m_data = new Q_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 Q_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 Q_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 Q_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; + + Q_UINT8 * m_data2 = new Q_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(Q_UINT8 * data, KisColorSpace * colorSpace) +{ + delete [] m_data; + m_data = new Q_UINT8[colorSpace->pixelSize()]; + memcpy(m_data, data, colorSpace->pixelSize()); + m_colorSpace = colorSpace; +} + +// To save the user the trouble of doing color->colorSpace()->toQColor(color->data(), &c, &a, profile +void KisColor::toQColor(QColor *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->toQColor(m_data, c); + } +} + +void KisColor::toQColor(QColor *c, Q_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->toQColor(m_data, c, opacity); + } +} + +QColor KisColor::toQColor() const +{ + QColor c; + toQColor(&c); + return c; +} + +void KisColor::dump() const +{ + + //kdDebug(DBG_AREA_CMS) << "KisColor (" << this << "), " << m_colorSpace->id().name() << "\n"; + QValueVector channels = m_colorSpace->channels(); + + QValueVector::const_iterator begin = channels.begin(); + QValueVector::const_iterator end = channels.end(); + + for (QValueVector::const_iterator it = begin; it != end; ++it) + { + KisChannelInfo * ch = (*it); + // XXX: setNum always takes a byte. + if (ch->size() == sizeof(Q_UINT8)) { + // Byte + //kdDebug(DBG_AREA_CMS) << "Channel (byte): " << ch->name() << ": " << QString().setNum(m_data[ch->pos()]) << "\n"; + } + else if (ch->size() == sizeof(Q_UINT16)) { + // Short (may also by an nvidia half) + //kdDebug(DBG_AREA_CMS) << "Channel (short): " << ch->name() << ": " << QString().setNum(*((const Q_UINT16 *)(m_data+ch->pos()))) << "\n"; + } + else if (ch->size() == sizeof(Q_UINT32)) { + // Integer (may also be float... Find out how to distinguish these!) + //kdDebug(DBG_AREA_CMS) << "Channel (int): " << ch->name() << ": " << QString().setNum(*((const Q_UINT32 *)(m_data+ch->pos()))) << "\n"; + } + } + +} diff --git a/krita/kritacolor/kis_color.h b/krita/kritacolor/kis_color.h new file mode 100644 index 00000000..647bddb3 --- /dev/null +++ b/krita/kritacolor/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 QColor. The QColor is immediately converted to native. The QColor + /// is assumed to have the current monitor profile. + KisColor(const QColor & color, KisColorSpace * colorSpace); + + /// Create a KisColor from a QColor. The QColor is immediately converted to native. The QColor + /// is assumed to have the current monitor profile. + KisColor(const QColor & color, Q_UINT8 alpha, KisColorSpace * colorSpace); + + /// Create a KisColor using a native color strategy. The data is copied. + KisColor(const Q_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. + Q_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(Q_UINT8 * data, KisColorSpace * colorSpace = 0); + + /// To save the user the trouble of doing color->colorSpace()->toQColor(color->data(), &c, &a + void toQColor(QColor *c) const; + void toQColor(QColor *c, Q_UINT8 *opacity) const; + + QColor toQColor() const; + + void dump() const; + +private: + + Q_UINT8 * m_data; + + KisColorSpace * m_colorSpace; +}; + +#endif diff --git a/krita/kritacolor/kis_color_conversions.cc b/krita/kritacolor/kis_color_conversions.cc new file mode 100644 index 00000000..2ba54ad5 --- /dev/null +++ b/krita/kritacolor/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 = QMAX(r, QMAX(g, b)); + float min = QMIN(r, QMIN(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(Q_UINT8 red, Q_UINT8 green, Q_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 = QMAX(r, g); + max = QMAX(max, b); + + min = QMIN(r, g); + min = QMIN(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, Q_UINT8 * r, Q_UINT8 * g, Q_UINT8 * b) +{ + float m1, m2; + + if (l <= 0.5 ) + m2 = l * ( 1 + s ); + else + m2 = l + s - l * s; + + m1 = 2 * l - m2; + + *r = (Q_UINT8)(hue_value(m1, m2, h + 120) * 255 + 0.5); + *g = (Q_UINT8)(hue_value(m1, m2, h) * 255 + 0.5); + *b = (Q_UINT8)(hue_value(m1, m2, h - 120) * 255 + 0.5); + +} + +void rgb_to_hls(Q_UINT8 r, Q_UINT8 g, Q_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, Q_UINT8 * r, Q_UINT8 * g, Q_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 = QMAX(r,g); + v = QMAX(v,b); + m = QMIN(r,g); + m = QMIN(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/krita/kritacolor/kis_color_conversions.h b/krita/kritacolor/kis_color_conversions.h new file mode 100644 index 00000000..011a50ea --- /dev/null +++ b/krita/kritacolor/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(Q_UINT8 r, Q_UINT8 g, Q_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, Q_UINT8 * r, Q_UINT8 * g, Q_UINT8 * b); + + void rgb_to_hls(Q_UINT8 r, Q_UINT8 g, Q_UINT8 b, int * h, int * l, int * s); + void hls_to_rgb(int h, int l, int s, Q_UINT8 * r, Q_UINT8 * g, Q_UINT8 * b); + +#endif // _KIS_CONVERSIONS_H_ + diff --git a/krita/kritacolor/kis_colorspace.cc b/krita/kritacolor/kis_colorspace.cc new file mode 100644 index 00000000..de0c44cf --- /dev/null +++ b/krita/kritacolor/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/krita/kritacolor/kis_colorspace.h b/krita/kritacolor/kis_colorspace.h new file mode 100644 index 00000000..0a94a74b --- /dev/null +++ b/krita/kritacolor/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 Krita. 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 QValueVector channels() const = 0; + + /** + * The total number of channels for a single pixel in this color model + */ + virtual Q_UINT32 nChannels() const = 0; + + /** + * The total number of color channels (excludes alpha and substance) for a single + * pixel in this color model. + */ + virtual Q_UINT32 nColorChannels() const = 0; + + /** + * The total number of substance channels for a single pixel + * in this color model + */ + virtual Q_UINT32 nSubstanceChannels() const { return 0; }; + + /** + * The size in bytes of a single pixel in this color model + */ + virtual Q_UINT32 pixelSize() const = 0; + + /** + * Return a string with the channel's value suitable for display in the gui. + */ + virtual QString channelValueText(const Q_UINT8 *pixel, Q_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 QString normalisedChannelValueText(const Q_UINT8 *pixel, Q_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 Q_UINT8 scaleToU8(const Q_UINT8 * srcPixel, Q_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 Q_UINT16 scaleToU16(const Q_UINT8 * srcPixel, Q_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(Q_UINT8 *dstPixel, const Q_UINT8 *srcPixel, Q_UINT32 channelIndex) = 0; + + //========== Identification ===============================================// + + /** + * Krita definition for use in .kra files and internally: unchanging name + + * i18n'able description. + */ + virtual KisID id() const = 0; + + /** + * lcms colorspace type definition. + */ + virtual Q_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 fromQColor methods take a given color defined as an RGB QColor + * and fills a byte array with the corresponding color in the + * the colorspace managed by this strategy. + * + * @param c the QColor 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 QColor + */ + virtual void fromQColor(const QColor& c, Q_UINT8 *dst, KisProfile * profile = 0) = 0; + + /** + * The fromQColor methods take a given color defined as an RGB QColor + * and fills a byte array with the corresponding color in the + * the colorspace managed by this strategy. + * + * @param c the QColor 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 QColor + */ + virtual void fromQColor(const QColor& c, Q_UINT8 opacity, Q_UINT8 *dst, KisProfile * profile = 0) = 0; + + + /** + * The toQColor methods take a byte array that is at least pixelSize() long + * and converts the contents to a QColor, 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 QColor 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 toQColor(const Q_UINT8 *src, QColor *c, KisProfile * profile = 0) = 0; + + /** + * The toQColor methods take a byte array that is at least pixelSize() long + * and converts the contents to a QColor, 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 QColor 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 toQColor(const Q_UINT8 *src, QColor *c, Q_UINT8 *opacity, KisProfile * profile = 0) = 0; + + /** + * Convert the pixels in data to (8-bit BGRA) QImage 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 QImage convertToQImage(const Q_UINT8 *data, Q_INT32 width, Q_INT32 height, + KisProfile * dstProfile, Q_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 Q_UINT8 * src, Q_UINT8 * dst, const Q_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 Q_UINT8 * src, Q_UINT8 * dst, const Q_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 Q_UINT8 * src, + Q_UINT8 * dst, KisColorSpace * dstColorSpace, + Q_UINT32 numPixels, + Q_INT32 renderingIntent = INTENT_PERCEPTUAL) = 0; + +//============================== Manipulation functions ==========================// + + +// +// The manipulation functions have default implementations that _convert_ the pixel +// to a QColor and back. Reimplement these methods in your color strategy! +// + + /** + * Get the alpha value of the given pixel, downscaled to an 8-bit value. + */ + virtual Q_UINT8 getAlpha(const Q_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(Q_UINT8 * pixels, Q_UINT8 alpha, Q_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(Q_UINT8 * pixels, Q_UINT8 alpha, Q_INT32 nPixels) = 0; + + /** + * Applies the specified 8-bit alpha mask 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(Q_UINT8 * pixels, Q_UINT8 * alpha, Q_INT32 nPixels) = 0; + + /** + * Applies the inverted 8-bit alpha mask 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(Q_UINT8 * pixels, Q_UINT8 * alpha, Q_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(Q_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(Q_UINT16 **transferValues) = 0; + + /** + * Apply the adjustment created with onr of the other functions + */ + virtual void applyAdjustment(const Q_UINT8 *src, Q_UINT8 *dst, KisColorAdjustment *, Q_INT32 nPixels) = 0; + + /** + * Invert color channels of the given pixels + */ + virtual void invertColor(Q_UINT8 * src, Q_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 Q_UINT8 difference(const Q_UINT8* src1, const Q_UINT8* src2) = 0; + + + /** + * Mix the colors given their weights and return in dst + * The sum of weights is assumed 255 */ + virtual void mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_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(Q_UINT8** colors, Q_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_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 Q_UINT8 * src, Q_UINT8 * dst, Q_INT32 shade, bool compensate, double compensation, Q_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 Q_UINT8 intensity8(const Q_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(Q_UINT8 *dst, + Q_INT32 dststride, + KisColorSpace * srcSpace, + const Q_UINT8 *src, + Q_INT32 srcRowStride, + const Q_UINT8 *srcAlphaMask, + Q_INT32 maskRowStride, + Q_UINT8 opacity, + Q_INT32 rows, + Q_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 QValueList createBackgroundFilters() + { return QValueList(); }; + +private: + + DCOPObject * m_dcop; + +}; + +class KisColorSpaceFactory { +public: + /** + * Krita definition for use in .kra files and internally: unchanging name + + * i18n'able description. + */ + virtual KisID id() const = 0; + + /** + * lcms colorspace type definition. + */ + virtual Q_UINT32 colorSpaceType() = 0; + + virtual icColorSpaceSignature colorSpaceSignature() = 0; + + virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *) = 0; + + /** + * Returns the default icc profile for use with this colorspace. This may be "" + * + & @return the default icc profile name + */ + virtual QString defaultProfile() = 0; + +}; + +#endif // KIS_COLORSPACE_H_ diff --git a/krita/kritacolor/kis_colorspace_factory_registry.cc b/krita/kritacolor/kis_colorspace_factory_registry.cc new file mode 100644 index 00000000..8aab0d9a --- /dev/null +++ b/krita/kritacolor/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(QStringList profileFilenames) +{ + // Create the built-in colorspaces + + m_alphaCs = new KisAlphaColorSpace(this, 0); + + // Load the profiles + if (!profileFilenames.empty()) { + KisProfile * profile = 0; + for ( QStringList::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(QString::fromLatin1("Krita/ColorSpace"), + QString::fromLatin1("(Type == 'Service') and " + "([X-Krita-Version] == 2)")); + + if (offers.empty()) { + KMessageBox::sorry(0, i18n("Cannot start Krita: 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, QStringList(), &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 QString & name) +{ + if (m_profileMap.find(name) == m_profileMap.end()) { + return 0; + } + + return m_profileMap[name]; +} + +QValueVector KisColorSpaceFactoryRegistry::profilesFor(KisID id) +{ + return profilesFor(get(id)); +} + +QValueVector KisColorSpaceFactoryRegistry::profilesFor(KisColorSpaceFactory * csf) +{ + + QValueVector profiles; + + QMap::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); +} + +QValueVector +KisColorSpaceFactoryRegistry::paintDeviceActionsFor(KisColorSpace* cs) { + return m_paintDevActionMap[cs->id()]; +} + +KisColorSpace * KisColorSpaceFactoryRegistry::getColorSpace(const KisID & csID, const QString & pName) +{ + QString profileName = pName; + + if(profileName.isEmpty()) + { + KisColorSpaceFactory *csf = get(csID); + + if(!csf) + return 0; + + profileName = csf->defaultProfile(); + } + + QString name = csID.id() + "" + profileName; + + if (m_csMap.find(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.contains(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; + + QString 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/krita/kritacolor/kis_colorspace_factory_registry.h b/krita/kritacolor/kis_colorspace_factory_registry.h new file mode 100644 index 00000000..2922a0e8 --- /dev/null +++ b/krita/kritacolor/kis_colorspace_factory_registry.h @@ -0,0 +1,120 @@ +/* + * 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 "qobject.h" +#include "kis_generic_registry.h" +#include "kis_colorspace.h" + +class QStringList; +class KisPaintDeviceAction; + +/** + * This class contains: + * - a registry of colorspace instantiated with specific profiles. + * - a registry of singleton colorspace factories. + * - a registry of icc profiles + */ +class KisColorSpaceFactoryRegistry : public QObject, public KisGenericRegistry { + + + Q_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(QStringList 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 QString & name); + + /** + * Return the vector of profiles for this colorspacefactory + */ + QValueVector profilesFor(KisColorSpaceFactory * cs); + + QValueVector profilesFor(KisID id); + + /** + * Return the colorspace + profile as named, or NULL if impossible combination. + */ + KisColorSpace * getColorSpace(const KisID & csID, const QString & 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 + */ + QValueVector paintDeviceActionsFor(KisColorSpace* cs); + +private: + KisColorSpaceFactoryRegistry(); + KisColorSpaceFactoryRegistry(const KisColorSpaceFactoryRegistry&); + KisColorSpaceFactoryRegistry operator=(const KisColorSpaceFactoryRegistry&); + +private: + + QMap m_profileMap; + QMap m_csMap; + typedef QValueVector PaintActionVector; + QMap m_paintDevActionMap; + KisColorSpace *m_alphaCs; +}; + +#endif // KIS_COLORSPACE_FACTORY_REGISTRY_H_ + diff --git a/krita/kritacolor/kis_colorspace_iface.cc b/krita/kritacolor/kis_colorspace_iface.cc new file mode 100644 index 00000000..5c7816c9 --- /dev/null +++ b/krita/kritacolor/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 * parent ) + : DCOPObject(parent->id().id().latin1()) +{ + m_parent = parent; +} + +QByteArray KisColorSpaceIface::invertColor(QByteArray src, Q_INT32 nPixels) +{ + m_parent->invertColor((Q_UINT8*)src.data(), nPixels); + return src; + +} + diff --git a/krita/kritacolor/kis_colorspace_iface.h b/krita/kritacolor/kis_colorspace_iface.h new file mode 100644 index 00000000..2243dc0f --- /dev/null +++ b/krita/kritacolor/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 * parent ); +k_dcop: + + QByteArray invertColor(QByteArray src, Q_INT32 nPixels); + +private: + + KisColorSpace *m_parent; +}; + +#endif diff --git a/krita/kritacolor/kis_composite_op.cc b/krita/kritacolor/kis_composite_op.cc new file mode 100644 index 00000000..3bdd0e4f --- /dev/null +++ b/krita/kritacolor/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 QString& 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/krita/kritacolor/kis_composite_op.h b/krita/kritacolor/kis_composite_op.h new file mode 100644 index 00000000..f6972f93 --- /dev/null +++ b/krita/kritacolor/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 QString& 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 QValueList KisCompositeOpList; + +#endif // KIS_COMPOSITE_OP_H diff --git a/krita/kritacolor/kis_f16half_base_colorspace.cc b/krita/kritacolor/kis_f16half_base_colorspace.cc new file mode 100644 index 00000000..be316408 --- /dev/null +++ b/krita/kritacolor/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" + +Q_UINT8 KisF16HalfBaseColorSpace::getAlpha(const Q_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(Q_UINT8 *U8_pixel, Q_UINT8 alpha, Q_INT32 nPixels) const +{ + if (m_alphaPos < 0) return; + Q_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(Q_UINT8 *U8_pixel, Q_UINT8 U8_alpha, Q_INT32 nPixels) +{ + if (m_alphaPos < 0) return; + Q_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(Q_UINT8 * U8_pixel, Q_UINT8 * alpha8, Q_INT32 nPixels) +{ + if (m_alphaPos < 0) return; + + Q_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(Q_UINT8 * U8_pixels, Q_UINT8 * alpha8, Q_INT32 nPixels) +{ + if (m_alphaPos < 0) return; + + Q_INT32 psize = pixelSize(); + + while (nPixels--) { + + half *pixelAlpha = reinterpret_cast(U8_pixels + m_alphaPos); + *pixelAlpha *= UINT8_TO_HALF(MAX_SELECTED - *alpha8); + + U8_pixels += psize; + ++alpha8; + } +} + +QString KisF16HalfBaseColorSpace::channelValueText(const Q_UINT8 *U8_pixel, Q_UINT32 channelIndex) const +{ + Q_ASSERT(channelIndex < (Q_UINT32)nChannels()); + const half *pixel = reinterpret_cast(U8_pixel); + Q_UINT32 channelPosition = channels()[channelIndex] -> pos() / sizeof(half); + + return QString().setNum(pixel[channelPosition]); +} + +QString KisF16HalfBaseColorSpace::normalisedChannelValueText(const Q_UINT8 *U8_pixel, Q_UINT32 channelIndex) const +{ + Q_ASSERT(channelIndex < (Q_UINT32)nChannels()); + const half *pixel = reinterpret_cast(U8_pixel); + Q_UINT32 channelPosition = channels()[channelIndex] -> pos() / sizeof(half); + + return QString().setNum(100.0 * pixel[channelPosition]); +} + +Q_UINT8 KisF16HalfBaseColorSpace::scaleToU8(const Q_UINT8 * U8_pixel, Q_INT32 channelPos) +{ + const half *pixelChannel = reinterpret_cast(U8_pixel + channelPos); + return HALF_TO_UINT8(*pixelChannel); +} + +Q_UINT16 KisF16HalfBaseColorSpace::scaleToU16(const Q_UINT8 * U8_pixel, Q_INT32 channelPos) +{ + const half *pixelChannel = reinterpret_cast(U8_pixel + channelPos); + return HALF_TO_UINT16(*pixelChannel); +} + diff --git a/krita/kritacolor/kis_f16half_base_colorspace.h b/krita/kritacolor/kis_f16half_base_colorspace.h new file mode 100644 index 00000000..1beb37c1 --- /dev/null +++ b/krita/kritacolor/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 * parent, + KisProfile *p) + : KisAbstractColorSpace(id, cmType, colorSpaceSignature, parent, p) + { + m_alphaSize = sizeof(half); + }; + + virtual Q_UINT8 getAlpha(const Q_UINT8 * pixel) const; + virtual void setAlpha(Q_UINT8 * pixels, Q_UINT8 alpha, Q_INT32 nPixels) const; + virtual void multiplyAlpha(Q_UINT8 * pixels, Q_UINT8 alpha, Q_INT32 nPixels); + + virtual void applyAlphaU8Mask(Q_UINT8 * pixels, Q_UINT8 * alpha, Q_INT32 nPixels); + virtual void applyInverseAlphaU8Mask(Q_UINT8 * pixels, Q_UINT8 * alpha, Q_INT32 nPixels); + + virtual QString channelValueText(const Q_UINT8 *pixel, Q_UINT32 channelIndex) const; + virtual QString normalisedChannelValueText(const Q_UINT8 *pixel, Q_UINT32 channelIndex) const; + + virtual Q_UINT8 scaleToU8(const Q_UINT8 * srcPixel, Q_INT32 channelPos); + virtual Q_UINT16 scaleToU16(const Q_UINT8 * srcPixel, Q_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 Q_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/krita/kritacolor/kis_f32_base_colorspace.cc b/krita/kritacolor/kis_f32_base_colorspace.cc new file mode 100644 index 00000000..2b6cc56d --- /dev/null +++ b/krita/kritacolor/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" + +Q_UINT8 KisF32BaseColorSpace::getAlpha(const Q_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(Q_UINT8 *U8_pixel, Q_UINT8 alpha, Q_INT32 nPixels) const +{ + if (m_alphaPos < 0) return; + Q_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(Q_UINT8 *U8_pixel, Q_UINT8 U8_alpha, Q_INT32 nPixels) +{ + if (m_alphaPos < 0) return; + Q_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(Q_UINT8 * U8_pixel, Q_UINT8 * alpha8, Q_INT32 nPixels) +{ + if (m_alphaPos < 0) return; + + Q_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(Q_UINT8 * U8_pixels, Q_UINT8 * alpha8, Q_INT32 nPixels) +{ + if (m_alphaPos < 0) return; + + Q_INT32 psize = pixelSize(); + + while (nPixels--) { + + float *pixelAlpha = reinterpret_cast(U8_pixels + m_alphaPos); + *pixelAlpha *= UINT8_TO_FLOAT(MAX_SELECTED - *alpha8); + + U8_pixels += psize; + ++alpha8; + } +} + +QString KisF32BaseColorSpace::channelValueText(const Q_UINT8 *U8_pixel, Q_UINT32 channelIndex) const +{ + Q_ASSERT(channelIndex < (Q_UINT32)nChannels()); + const float *pixel = reinterpret_cast(U8_pixel); + Q_UINT32 channelPosition = channels()[channelIndex]->pos() / sizeof(float); + + return QString().setNum(pixel[channelPosition]); +} + +QString KisF32BaseColorSpace::normalisedChannelValueText(const Q_UINT8 *U8_pixel, Q_UINT32 channelIndex) const +{ + Q_ASSERT(channelIndex < (Q_UINT32)nChannels()); + const float *pixel = reinterpret_cast(U8_pixel); + Q_UINT32 channelPosition = channels()[channelIndex]->pos() / sizeof(float); + + return QString().setNum(100.0 * pixel[channelPosition]); +} + +Q_UINT8 KisF32BaseColorSpace::scaleToU8(const Q_UINT8 * U8_pixel, Q_INT32 channelPos) +{ + const float *pixelChannel = reinterpret_cast(U8_pixel + channelPos); + return FLOAT_TO_UINT8(*pixelChannel); +} + +Q_UINT16 KisF32BaseColorSpace::scaleToU16(const Q_UINT8 * U8_pixel, Q_INT32 channelPos) +{ + const float *pixelChannel = reinterpret_cast(U8_pixel + channelPos); + return FLOAT_TO_UINT16(*pixelChannel); +} + diff --git a/krita/kritacolor/kis_f32_base_colorspace.h b/krita/kritacolor/kis_f32_base_colorspace.h new file mode 100644 index 00000000..f3a9ac28 --- /dev/null +++ b/krita/kritacolor/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 * parent, KisProfile *p) + : KisAbstractColorSpace(id, cmType, colorSpaceSignature, parent, p) + { + m_alphaSize = sizeof(float); + }; + + virtual Q_UINT8 getAlpha(const Q_UINT8 * pixel) const; + virtual void setAlpha(Q_UINT8 * pixels, Q_UINT8 alpha, Q_INT32 nPixels) const; + virtual void multiplyAlpha(Q_UINT8 * pixels, Q_UINT8 alpha, Q_INT32 nPixels); + + virtual void applyAlphaU8Mask(Q_UINT8 * pixels, Q_UINT8 * alpha, Q_INT32 nPixels); + virtual void applyInverseAlphaU8Mask(Q_UINT8 * pixels, Q_UINT8 * alpha, Q_INT32 nPixels); + + virtual QString channelValueText(const Q_UINT8 *pixel, Q_UINT32 channelIndex) const; + virtual QString normalisedChannelValueText(const Q_UINT8 *pixel, Q_UINT32 channelIndex) const; + + virtual Q_UINT8 scaleToU8(const Q_UINT8 * srcPixel, Q_INT32 channelPos); + virtual Q_UINT16 scaleToU16(const Q_UINT8 * srcPixel, Q_INT32 channelPos); + + virtual bool hasHighDynamicRange() const { return true; } +}; + +#endif // KIS_F32_BASE_COLORSPACE_H_ diff --git a/krita/kritacolor/kis_histogram_producer.cc b/krita/kritacolor/kis_histogram_producer.cc new file mode 100644 index 00000000..ae61e7cf --- /dev/null +++ b/krita/kritacolor/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; + QValueList 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); + QValueList::iterator pit = preferredList.begin(); + QValueList::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/krita/kritacolor/kis_histogram_producer.h b/krita/kritacolor/kis_histogram_producer.h new file mode 100644 index 00000000..171ab1b0 --- /dev/null +++ b/krita/kritacolor/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 QString; +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(Q_UINT8 * pixels, Q_UINT8 * selectionMask, Q_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 QValueVector channels() = 0; + virtual Q_INT32 numberOfBins() = 0; + virtual QString 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 Q_INT32 count() = 0; + virtual Q_INT32 getBinAt(Q_INT32 channel, Q_INT32 position) = 0; + virtual Q_INT32 outOfViewLeft(Q_INT32 channel) = 0; + virtual Q_INT32 outOfViewRight(Q_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/krita/kritacolor/kis_profile.cc b/krita/kritacolor/kis_profile.cc new file mode 100644 index 00000000..83880398 --- /dev/null +++ b/krita/kritacolor/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(QByteArray rawData) + : m_rawData(rawData), + m_filename( QString() ), + m_valid( false ), + m_suitableForOutput(false) +{ + m_profile = cmsOpenProfileFromMem(rawData.data(), (DWORD)rawData.size()); + init(); +} + +KisProfile::KisProfile(const QString& file) + : m_filename(file), + m_valid( false ), + m_suitableForOutput( false ) +{ +} + +KisProfile::KisProfile(const cmsHPROFILE profile) + : m_profile(profile), + m_filename( QString() ), + 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.resize(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() +{ + QFile 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) { + QFile 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; + Q_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) + ) { + + QByteArray bytes (nitems); + bytes.assign((char*)str, (Q_UINT32)nitems); + + return new KisProfile(bytes); + } else { + return NULL; + } +#else + return NULL; + +#endif +} + + diff --git a/krita/kritacolor/kis_profile.h b/krita/kritacolor/kis_profile.h new file mode 100644 index 00000000..075b8060 --- /dev/null +++ b/krita/kritacolor/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(QByteArray rawData); + KisProfile(const QString& 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 QString productName() const { return m_productName; } + inline QString productDescription() const { return m_productDescription; } + inline QString productInfo() const { return m_productInfo; } + inline QString 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 QString filename() const { return m_filename; } + +public: + + static KisProfile * getScreenProfile(int screen = -1); + +private: + bool init(); + + cmsHPROFILE m_profile; + icColorSpaceSignature m_colorSpaceSignature; + icProfileClassSignature m_deviceClass; + QString m_productName; + QString m_productDescription; + QString m_productInfo; + QString m_manufacturer; + + QByteArray m_rawData; + + QString 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/krita/kritacolor/kis_u16_base_colorspace.cc b/krita/kritacolor/kis_u16_base_colorspace.cc new file mode 100644 index 00000000..45d72d0c --- /dev/null +++ b/krita/kritacolor/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" + + +Q_UINT8 KisU16BaseColorSpace::getAlpha(const Q_UINT8 * U8_pixel) const +{ + if (m_alphaPos < 0) return OPACITY_OPAQUE; + + U8_pixel+= m_alphaPos; + + const Q_UINT16 *pixel = reinterpret_cast(U8_pixel); + return UINT16_TO_UINT8(*pixel); +} + + +void KisU16BaseColorSpace::setAlpha(Q_UINT8 *U8_pixel, Q_UINT8 alpha, Q_INT32 nPixels) const +{ + if (m_alphaPos < 0) return; + Q_INT32 psize = pixelSize(); + + + while (nPixels > 0) { + + Q_UINT16 *pixel = reinterpret_cast(U8_pixel + m_alphaPos); + pixel[0] = UINT8_TO_UINT16(alpha); + + --nPixels; + U8_pixel += psize; + } +} + +void KisU16BaseColorSpace::multiplyAlpha(Q_UINT8 *U8_pixel, Q_UINT8 U8_alpha, Q_INT32 nPixels) +{ + if (m_alphaPos < 0) return; + + Q_INT32 psize = pixelSize(); + Q_UINT16 alpha = UINT8_TO_UINT16(U8_alpha); + + while (nPixels > 0) { + + Q_UINT16 *pixelAlpha = reinterpret_cast(U8_pixel + m_alphaPos); + *pixelAlpha = UINT16_MULT(*pixelAlpha, alpha); + + --nPixels; + U8_pixel += psize; + } +} + +void KisU16BaseColorSpace::applyAlphaU8Mask(Q_UINT8 * U8_pixel, Q_UINT8 * alpha8, Q_INT32 nPixels) +{ + if (m_alphaPos < 0) return; + + Q_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. + + Q_UINT16 *pixelAlpha = reinterpret_cast(U8_pixel + m_alphaPos); + *pixelAlpha = UINT8_MULT(*pixelAlpha, *alpha8); + + ++alpha8; + U8_pixel += psize; + + } +} + +void KisU16BaseColorSpace::applyInverseAlphaU8Mask(Q_UINT8 * U8_pixels, Q_UINT8 * alpha8, Q_INT32 nPixels) +{ + + if (m_alphaPos < 0) return; + + Q_INT32 psize = pixelSize(); + + + while(nPixels--) { + + Q_UINT16 s_alpha8; + Q_UINT32 p_alpha, s_alpha16; + + Q_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; + } +} + +QString KisU16BaseColorSpace::channelValueText(const Q_UINT8 *U8_pixel, Q_UINT32 channelIndex) const +{ + Q_ASSERT(channelIndex < (Q_UINT32)nChannels()); + const Q_UINT16 *pixel = reinterpret_cast(U8_pixel); + Q_UINT32 channelPosition = channels()[channelIndex]->pos() / sizeof(Q_UINT16); + + return QString().setNum(pixel[channelPosition]); +} + +QString KisU16BaseColorSpace::normalisedChannelValueText(const Q_UINT8 *U8_pixel, Q_UINT32 channelIndex) const +{ + Q_ASSERT(channelIndex < (Q_UINT32)nChannels()); + const Q_UINT16 *pixel = reinterpret_cast(U8_pixel); + Q_UINT32 channelPosition = m_channels[channelIndex]->pos() / sizeof(Q_UINT16); + + return QString().setNum(100.0 * static_cast(pixel[channelPosition]) / UINT16_MAX); +} + +Q_UINT8 KisU16BaseColorSpace::scaleToU8(const Q_UINT8 * U8_pixel, Q_INT32 channelPos) +{ + const Q_UINT16 *pixel = reinterpret_cast(U8_pixel); + return UINT16_TO_UINT8(pixel[channelPos]); +} + +Q_UINT16 KisU16BaseColorSpace::scaleToU16(const Q_UINT8 * U8_pixel, Q_INT32 channelPos) +{ + const Q_UINT16 *pixel = reinterpret_cast(U8_pixel); + return pixel[channelPos]; +} + diff --git a/krita/kritacolor/kis_u16_base_colorspace.h b/krita/kritacolor/kis_u16_base_colorspace.h new file mode 100644 index 00000000..aedd5a2e --- /dev/null +++ b/krita/kritacolor/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 Q_UINT16 U16_OPACITY_OPAQUE = UINT16_MAX; + static const Q_UINT16 U16_OPACITY_TRANSPARENT = UINT16_MIN; + +public: + + KisU16BaseColorSpace(const KisID & id, DWORD cmType, icColorSpaceSignature colorSpaceSignature, + KisColorSpaceFactoryRegistry * parent, + KisProfile *p) + : KisAbstractColorSpace(id, cmType, colorSpaceSignature, + parent, + p) + { + m_alphaSize = sizeof(Q_UINT16); + }; + + virtual Q_UINT8 getAlpha(const Q_UINT8 * pixel) const; + virtual void setAlpha(Q_UINT8 * pixels, Q_UINT8 alpha, Q_INT32 nPixels) const; + virtual void multiplyAlpha(Q_UINT8 * pixels, Q_UINT8 alpha, Q_INT32 nPixels); + + virtual void applyAlphaU8Mask(Q_UINT8 * pixels, Q_UINT8 * alpha, Q_INT32 nPixels); + virtual void applyInverseAlphaU8Mask(Q_UINT8 * pixels, Q_UINT8 * alpha, Q_INT32 nPixels); + + virtual QString channelValueText(const Q_UINT8 *pixel, Q_UINT32 channelIndex) const; + virtual QString normalisedChannelValueText(const Q_UINT8 *pixel, Q_UINT32 channelIndex) const; + + virtual Q_UINT8 scaleToU8(const Q_UINT8 * srcPixel, Q_INT32 channelPos); + virtual Q_UINT16 scaleToU16(const Q_UINT8 * srcPixel, Q_INT32 channelPos); + +protected: + // For Alpha Composite + struct U16Mult { + inline Q_UINT16 operator()(const Q_UINT16& a, const Q_UINT16& b) const { + return UINT16_MULT(a, b); + } + }; + struct Uint8ToU16 { + inline Q_UINT16 operator()(const Q_UINT8 src) const { + return UINT8_TO_UINT16(src); + } + }; + struct U16OpacityTest { + inline bool operator()(const Q_UINT16& opacity) const { + return opacity != U16_OPACITY_TRANSPARENT; + } + }; +}; +#endif // KIS_U16_BASE_COLORSPACE_H_ diff --git a/krita/kritacolor/kis_u8_base_colorspace.cc b/krita/kritacolor/kis_u8_base_colorspace.cc new file mode 100644 index 00000000..ec0003fc --- /dev/null +++ b/krita/kritacolor/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" + +Q_UINT8 KisU8BaseColorSpace::getAlpha(const Q_UINT8 * pixel) const +{ + return pixel[m_alphaPos]; +} + + + +void KisU8BaseColorSpace::setAlpha(Q_UINT8 * pixels, Q_UINT8 alpha, Q_INT32 nPixels) const +{ + if (m_alphaPos < 0) return; + Q_INT32 psize = pixelSize(); + + pixels += m_alphaPos; + while (nPixels > 0) { + *pixels = alpha; + --nPixels; + pixels += psize; + } + +} + +void KisU8BaseColorSpace::multiplyAlpha(Q_UINT8 * pixels, Q_UINT8 alpha, Q_INT32 nPixels) +{ + if (m_alphaPos < 0) return; + Q_INT32 psize = pixelSize(); + + while (nPixels > 0) { + pixels[m_alphaPos] = UINT8_MULT(pixels[m_alphaPos], alpha); + --nPixels; + pixels += psize; + } +} + +void KisU8BaseColorSpace::applyAlphaU8Mask(Q_UINT8 * pixels, Q_UINT8 * alpha, Q_INT32 nPixels) +{ + Q_INT32 psize = pixelSize(); + + while (nPixels--) { + + pixels[m_alphaPos] = UINT8_MULT(*(pixels + m_alphaPos) , *alpha); + + alpha++; + pixels += psize; + + } +} + +void KisU8BaseColorSpace::applyInverseAlphaU8Mask(Q_UINT8 * pixels, Q_UINT8 * alpha, Q_INT32 nPixels) +{ + Q_INT32 psize = pixelSize(); + + while(nPixels--) { + + Q_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; + } +} + +QString KisU8BaseColorSpace::channelValueText(const Q_UINT8 *pixel, Q_UINT32 channelIndex) const +{ + Q_ASSERT(channelIndex < (Q_UINT32)nChannels()); + Q_UINT32 channelPosition = m_channels[channelIndex]->pos(); + + return QString().setNum(pixel[channelPosition]); +} + +QString KisU8BaseColorSpace::normalisedChannelValueText(const Q_UINT8 *pixel, Q_UINT32 channelIndex) const +{ + Q_ASSERT(channelIndex < (Q_UINT32)nChannels()); + Q_UINT32 channelPosition = m_channels[channelIndex]->pos(); + + return QString().setNum(100.0 * static_cast(pixel[channelPosition]) / UINT8_MAX); +} + + +Q_UINT8 KisU8BaseColorSpace::scaleToU8(const Q_UINT8 * pixel, Q_INT32 channelPos) +{ + return pixel[channelPos]; +} + +Q_UINT16 KisU8BaseColorSpace::scaleToU16(const Q_UINT8 * pixel, Q_INT32 channelPos) +{ + return UINT8_TO_UINT16(pixel[channelPos]); +} + diff --git a/krita/kritacolor/kis_u8_base_colorspace.h b/krita/kritacolor/kis_u8_base_colorspace.h new file mode 100644 index 00000000..fc830e99 --- /dev/null +++ b/krita/kritacolor/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 * parent, + KisProfile *p) + : KisAbstractColorSpace(id, cmType, colorSpaceSignature, parent, p) + { + m_alphaSize = sizeof(Q_UINT8); + }; + + virtual Q_UINT8 getAlpha(const Q_UINT8 * pixel) const; + virtual void setAlpha(Q_UINT8 * pixels, Q_UINT8 alpha, Q_INT32 nPixels) const; + virtual void multiplyAlpha(Q_UINT8 * pixels, Q_UINT8 alpha, Q_INT32 nPixels); + + virtual void applyAlphaU8Mask(Q_UINT8 * pixels, Q_UINT8 * alpha, Q_INT32 nPixels); + virtual void applyInverseAlphaU8Mask(Q_UINT8 * pixels, Q_UINT8 * alpha, Q_INT32 nPixels); + + virtual QString channelValueText(const Q_UINT8 *pixel, Q_UINT32 channelIndex) const; + virtual QString normalisedChannelValueText(const Q_UINT8 *pixel, Q_UINT32 channelIndex) const; + + virtual Q_UINT8 scaleToU8(const Q_UINT8 * srcPixel, Q_INT32 channelPos); + virtual Q_UINT16 scaleToU16(const Q_UINT8 * srcPixel, Q_INT32 channelPos); + +protected: + // For Alpha Composite + struct U8Mult { + inline Q_UINT8 operator()(const Q_UINT8& a, const Q_UINT8& b) const { + return UINT8_MULT(a, b); + } + }; + struct Uint8ToU8 { + inline Q_UINT8 operator()(const Q_UINT8 src) const { + return src; + } + }; + struct U8OpacityTest { + inline bool operator()(const Q_UINT8& opacity) const { + return opacity != OPACITY_TRANSPARENT; + } + }; +}; + + +#endif // KIS_U8_BASE_COLORSPACE_H_ diff --git a/krita/kritacolor/krita_colorspace.desktop b/krita/kritacolor/krita_colorspace.desktop new file mode 100644 index 00000000..c3db30c3 --- /dev/null +++ b/krita/kritacolor/krita_colorspace.desktop @@ -0,0 +1,38 @@ +[Desktop Entry] +Type=ServiceType +X-KDE-ServiceType=Krita/ColorSpace +Comment=A module implementing a complete colorspace for use with libkritacolor +Comment[bg]=Модул, реализиращ пълна цветова гама за употреба с libkritacolor +Comment[ca]=Un mòdul que implementa un complet espai de colors per a usar-lo amb libkritacolor +Comment[cy]=Modiwl sy'n gweithredoli gofod lliw cyflawn i'w ddefnyddio efo libkritacolor +Comment[da]=Et modul som implementerer et fuldstændigt farverum til brug med libkritacolor +Comment[de]=Ein Modul, das einen kompletten Farbraum zur Benutzung mit libkritacolor implementiert +Comment[el]=Ένα άρθρωμα που υλοποιεί έναν πλήρη χρωματικό χώρο για χρήση με το libkritacolor +Comment[en_GB]=A module implementing a complete colourspace for use with libkritacolor +Comment[es]=Un módulo que implementa un espacio de color completo para usar con libkritacolor +Comment[et]=Täielikku värviruumi teostav moodul (teegile libkritacolor) +Comment[fa]=پیمانه‌ای که فضای رنگ کاملی برای استفاده با libkritacolor پیاده می‌کند +Comment[fr]=Un module implantant un espace de couleurs complet à utiliser avec libkritacolor +Comment[fy]=In module dy in folslein kleurgebiet ymplementearret dat brûkt wurde kin mei libkritacolor +Comment[gl]=Un módulo que implemente un espazo de cor completo para usar con libkritacolor +Comment[hu]=Teljes színteret megvalósító modul a libkritacolor programkönyvtárhoz +Comment[is]=Eining með fullu litasvæði til notkunar með libkritacolor +Comment[it]=Un modulo che implementa uno spazio dei colori completo per usarlo con libkritacolor +Comment[km]=ម៉ូឌុល​ដែល​អនុវត្ត​ប្រភេទ​ពណ៌​ពេញលេញ ដើម្បី​ប្រើ​ជាមួយ libkritacolor +Comment[nb]=En modul som implementerer et komplett fargerom til bruk med libkritacolor +Comment[nds]=En Moduul, dat en helen Klörenruum för den Bruuk mit libkritacolor inbuut +Comment[ne]=लिबक्रितारङसँग प्रयोग गर्नका लागि सम्पूर्ण रङ खालीस्थानलाई मोड्युललाई औजार बनाइदै +Comment[nl]=Een module die een volledig kleurgebied implementeert dat gebruikt kan worden met libkritacolor +Comment[pl]=Moduł implementujący kompletną przestrzeń barw do użytku z libkritacolor +Comment[pt]=Um módulo que implementa um espaço de cores completo para usar com a 'libkritacolor' +Comment[pt_BR]=Um módulo que implementa um espaço de cores completo para usar com a 'libkritacolor' +Comment[ru]=Полная поддержка цветовых пространств в libkritacolor +Comment[sk]=Modul ktorý poskytuje úplný farebný priestor pre použitie s libkritacolor +Comment[sl]=Modul, v katerem je izveden celoten barvni prostor za uporabo z libkritacolor +Comment[sr]=Модул који имплементира потпун простор боја за употребу са libkritacolor +Comment[sr@Latn]=Modul koji implementira potpun prostor boja za upotrebu sa libkritacolor +Comment[sv]=En modul som implementerar en fullständig färgrymd för användning med libkritacolor +Comment[uk]=Модуль впровадження повного простору кольорів для вжитку з libkritacolor +Comment[zh_TW]=實作完整色彩空間以使用 libkritacolor 的模組 +[PropertyDef::X-Krita-Version] +Type=int diff --git a/krita/kritacolor/tests/Makefile.am b/krita/kritacolor/tests/Makefile.am new file mode 100644 index 00000000..86bd6ded --- /dev/null +++ b/krita/kritacolor/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 ../libkritacolor.la ../../libkritacommon.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/krita/kritacolor/tests/kis_color_conversions_tester.cpp b/krita/kritacolor/tests/kis_color_conversions_tester.cpp new file mode 100644 index 00000000..d244b5dd --- /dev/null +++ b/krita/kritacolor/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/krita/kritacolor/tests/kis_color_conversions_tester.h b/krita/kritacolor/tests/kis_color_conversions_tester.h new file mode 100644 index 00000000..f21eca59 --- /dev/null +++ b/krita/kritacolor/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(QString(__FILE__) + "[" + QString::number(__LINE__) + "]: passed " + #x); \ +} \ +else \ +{ \ + failure(QString(__FILE__) + "[" + QString::number(__LINE__) + QString("]: failed ") + #x + "\n Expected " + #y + ", Actual result " + QString::number(x)); \ +} \ + + +class KisColorConversionsTester : public KUnitTest::Tester +{ +public: + void allTests(); + void testRGBHSV(); + void testRGBHSL(); +}; + +#endif + diff --git a/krita/kritapart.desktop b/krita/kritapart.desktop new file mode 100644 index 00000000..e465cc10 --- /dev/null +++ b/krita/kritapart.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=libkritapart +MimeType=application/x-krita +Type=Service +ServiceTypes=KOfficePart,KParts/ReadOnlyPart,KParts/ReadWritePart +X-KDE-NativeMimeType=application/x-krita +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=krita +X-Krita-Version=2 diff --git a/krita/main.cc b/krita/main.cc new file mode 100644 index 00000000..0bfe9643 --- /dev/null +++ b/krita/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, newKritaAboutData()); + KCmdLineArgs::addCmdLineOptions(options); + + KoApplication app; + + if (!app.start()) + return 1; + + return app.exec(); +} + diff --git a/krita/pics/Makefile.am b/krita/pics/Makefile.am new file mode 100644 index 00000000..f265f03d --- /dev/null +++ b/krita/pics/Makefile.am @@ -0,0 +1,22 @@ + +kritapics_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 +kritapicsdir = $(kde_datadir)/krita/pics + +KDE_ICON = krita + + + + diff --git a/krita/pics/deletelayer.png b/krita/pics/deletelayer.png new file mode 100644 index 00000000..9883939c Binary files /dev/null and b/krita/pics/deletelayer.png differ diff --git a/krita/pics/height.png b/krita/pics/height.png new file mode 100644 index 00000000..81aa9fcf Binary files /dev/null and b/krita/pics/height.png differ diff --git a/krita/pics/hi128-app-krita.png b/krita/pics/hi128-app-krita.png new file mode 100644 index 00000000..ed61e91d Binary files /dev/null and b/krita/pics/hi128-app-krita.png differ diff --git a/krita/pics/hi16-app-krita.png b/krita/pics/hi16-app-krita.png new file mode 100644 index 00000000..45a06245 Binary files /dev/null and b/krita/pics/hi16-app-krita.png differ diff --git a/krita/pics/hi22-app-krita.png b/krita/pics/hi22-app-krita.png new file mode 100644 index 00000000..be323526 Binary files /dev/null and b/krita/pics/hi22-app-krita.png differ diff --git a/krita/pics/hi32-app-krita.png b/krita/pics/hi32-app-krita.png new file mode 100644 index 00000000..9a372e6f Binary files /dev/null and b/krita/pics/hi32-app-krita.png differ diff --git a/krita/pics/hi48-app-krita.png b/krita/pics/hi48-app-krita.png new file mode 100644 index 00000000..c69aadde Binary files /dev/null and b/krita/pics/hi48-app-krita.png differ diff --git a/krita/pics/hi64-app-krita.png b/krita/pics/hi64-app-krita.png new file mode 100644 index 00000000..a9f3e343 Binary files /dev/null and b/krita/pics/hi64-app-krita.png differ diff --git a/krita/pics/krita.svg b/krita/pics/krita.svg new file mode 100644 index 00000000..23035ac3 --- /dev/null +++ b/krita/pics/krita.svg @@ -0,0 +1,509 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/krita/pics/linked.png b/krita/pics/linked.png new file mode 100644 index 00000000..765baffe Binary files /dev/null and b/krita/pics/linked.png differ diff --git a/krita/pics/locked.png b/krita/pics/locked.png new file mode 100644 index 00000000..e8d0d2d1 Binary files /dev/null and b/krita/pics/locked.png differ diff --git a/krita/pics/lowerlayer.png b/krita/pics/lowerlayer.png new file mode 100644 index 00000000..0b18da49 Binary files /dev/null and b/krita/pics/lowerlayer.png differ diff --git a/krita/pics/newlayer.png b/krita/pics/newlayer.png new file mode 100644 index 00000000..d4736bb9 Binary files /dev/null and b/krita/pics/newlayer.png differ diff --git a/krita/pics/novisible.png b/krita/pics/novisible.png new file mode 100644 index 00000000..15e30c1b Binary files /dev/null and b/krita/pics/novisible.png differ diff --git a/krita/pics/raiselayer.png b/krita/pics/raiselayer.png new file mode 100644 index 00000000..619d8742 Binary files /dev/null and b/krita/pics/raiselayer.png differ diff --git a/krita/pics/shade.png b/krita/pics/shade.png new file mode 100644 index 00000000..590fb57d Binary files /dev/null and b/krita/pics/shade.png differ diff --git a/krita/pics/tablet.png b/krita/pics/tablet.png new file mode 100644 index 00000000..f019a704 Binary files /dev/null and b/krita/pics/tablet.png differ diff --git a/krita/pics/tool_screenshot.png b/krita/pics/tool_screenshot.png new file mode 100644 index 00000000..0e234242 Binary files /dev/null and b/krita/pics/tool_screenshot.png differ diff --git a/krita/pics/unlinked.png b/krita/pics/unlinked.png new file mode 100644 index 00000000..71bbb11d Binary files /dev/null and b/krita/pics/unlinked.png differ diff --git a/krita/pics/unlocked.png b/krita/pics/unlocked.png new file mode 100644 index 00000000..e2d1741b Binary files /dev/null and b/krita/pics/unlocked.png differ diff --git a/krita/pics/visible.png b/krita/pics/visible.png new file mode 100644 index 00000000..735de7e8 Binary files /dev/null and b/krita/pics/visible.png differ diff --git a/krita/pics/width.png b/krita/pics/width.png new file mode 100644 index 00000000..fefb43a1 Binary files /dev/null and b/krita/pics/width.png differ diff --git a/krita/plugins/Makefile.am b/krita/plugins/Makefile.am new file mode 100644 index 00000000..468df77e --- /dev/null +++ b/krita/plugins/Makefile.am @@ -0,0 +1,5 @@ +SUBDIRS = \ + filters \ + paintops \ + tools \ + viewplugins diff --git a/krita/plugins/README b/krita/plugins/README new file mode 100644 index 00000000..31518552 --- /dev/null +++ b/krita/plugins/README @@ -0,0 +1,42 @@ +About plugins + +Plugins are components with a GUI that perform some action for Krita. +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 Krita: + +* Tools + + Tools have the Krita/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 Krita/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 Krita/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 Krita/Plugin. They are not loaded automatically by + the KParts mechanism; please do not create ordinary kparts that are to + be loaded by the Krita view since KParts are not versioned. diff --git a/krita/plugins/configure.in.in b/krita/plugins/configure.in.in new file mode 100644 index 00000000..c1845fdc --- /dev/null +++ b/krita/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/krita/plugins/filters/Makefile.am b/krita/plugins/filters/Makefile.am new file mode 100644 index 00000000..19ff6736 --- /dev/null +++ b/krita/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/krita/plugins/filters/blur/Makefile.am b/krita/plugins/filters/blur/Makefile.am new file mode 100644 index 00000000..5d89ac20 --- /dev/null +++ b/krita/plugins/filters/blur/Makefile.am @@ -0,0 +1,21 @@ +kritarcdir = $(kde_datadir)/krita/kritaplugins + +kde_services_DATA = kritablurfilter.desktop + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kritablurfilter_la_SOURCES = wdgblur.ui blur.cc kis_blur_filter.cc kis_wdg_blur.cc + +kde_module_LTLIBRARIES = kritablurfilter.la +noinst_HEADERS = blur.h kis_blur_filter.h + +kritablurfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritablurfilter_la_LIBADD = ../../../libkritacommon.la + +METASOURCES = AUTO + diff --git a/krita/plugins/filters/blur/blur.cc b/krita/plugins/filters/blur/blur.cc new file mode 100644 index 00000000..14d815b4 --- /dev/null +++ b/krita/plugins/filters/blur/blur.cc @@ -0,0 +1,50 @@ +/* + * This file is part of Krita + * + * 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( kritablurfilter, BlurFilterPluginFactory( "krita" ) ) + +BlurFilterPlugin::BlurFilterPlugin(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(BlurFilterPluginFactory::instance()); + + + kdDebug(41006) << "Extensions Convolution Filters plugin. Class: " + << className() + << ", Parent: " + << parent -> className() + << "\n"; + + if (parent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(parent); + manager->add(new KisBlurFilter()); + } +} + +BlurFilterPlugin::~BlurFilterPlugin() +{ +} diff --git a/krita/plugins/filters/blur/blur.h b/krita/plugins/filters/blur/blur.h new file mode 100644 index 00000000..a0c51579 --- /dev/null +++ b/krita/plugins/filters/blur/blur.h @@ -0,0 +1,37 @@ +/* + * This file is part of Krita + * + * 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(QObject *parent, const char *name, const QStringList &); + virtual ~BlurFilterPlugin(); +}; + +#endif diff --git a/krita/plugins/filters/blur/kis_blur_filter.cc b/krita/plugins/filters/blur/kis_blur_filter.cc new file mode 100644 index 00000000..5970cb6e --- /dev/null +++ b/krita/plugins/filters/blur/kis_blur_filter.cc @@ -0,0 +1,143 @@ +/* + * This file is part of Krita + * + * 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 kernelFromQImage(const QImage& 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 Q_INT32[count]; + Q_INT32* itData = k->data; + Q_UINT8* itImg = 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(QWidget* parent, KisPaintDeviceSP ) +{ + return new KisWdgBlur(this, parent, "configuration of color to alpha"); +} + +KisFilterConfiguration* KisBlurFilter::configuration(QWidget* 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("shape", wCTA->widget()->cbShape->currentItem()); + } + return config; +} + +void KisBlurFilter::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* config, const QRect& rect) +{ + Q_ASSERT(src != 0); + Q_ASSERT(dst != 0); + + setProgressTotalSteps(rect.width() * rect.height()); + + if(!config) config = new KisFilterConfiguration(id().id(), 1); + + QVariant value; + int shape = (config->getProperty("shape", 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(shape) + { + case 1: + kas = new KisAutobrushRectShape(width, height , hFade, vFade); + break; + case 0: + default: + kas = new KisAutobrushCircleShape(width, height, hFade, vFade); + break; + } + QImage mask; + kas->createBrush(&mask); + + mask.convertDepth(1); + + if( rotate != 0) + { + QWMatrix m; + m.rotate( rotate ); + mask = mask.xForm( m ); + if( (mask.height() & 1) || mask.width() & 1) + { + mask.smoothScale( mask.width() + !(mask.width() & 1), mask.height() + !(mask.height() & 1) ); + } + } + + KisConvolutionPainter painter( dst ); + if (m_progressDisplay) + m_progressDisplay->setSubject( &painter, true, true ); + + KisKernelSP kernel = kernelFromQImage(mask); // TODO: for 1.6 reuse the krita's core function for creating kernel : KisKernel::fromQImage + + 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/krita/plugins/filters/blur/kis_blur_filter.h b/krita/plugins/filters/blur/kis_blur_filter.h new file mode 100644 index 00000000..781c090e --- /dev/null +++ b/krita/plugins/filters/blur/kis_blur_filter.h @@ -0,0 +1,49 @@ +/* + * This file is part of Krita + * + * 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 QRect&); + 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(QWidget* parent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(QWidget*); +}; + +#endif diff --git a/krita/plugins/filters/blur/kis_wdg_blur.cc b/krita/plugins/filters/blur/kis_wdg_blur.cc new file mode 100644 index 00000000..dd53e09a --- /dev/null +++ b/krita/plugins/filters/blur/kis_wdg_blur.cc @@ -0,0 +1,116 @@ +/* + * This file is part of Krita + * + * 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, QWidget * parent, const char * name) : KisFilterConfigWidget ( parent, name ) +{ + Q_UNUSED( nfilter ); + + QGridLayout *widgetLayout = new QGridLayout(this, 1, 1); + m_widget = new WdgBlur(this); + widgetLayout -> addWidget(m_widget,0,0); + + linkSpacingToggled(true); + + connect( widget()->bnLinkSize, SIGNAL(toggled(bool)), this, SLOT(linkSpacingToggled( bool ))); + connect( widget()->intHalfWidth, SIGNAL(valueChanged(int)),this,SLOT(spinBoxHalfWidthChanged(int))); + connect( widget()->intHalfHeight, SIGNAL(valueChanged(int)),this,SLOT(spinBoxHalfHeightChanged(int))); + + connect( widget()->intStrength, SIGNAL( valueChanged(int)), SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->intAngle, SIGNAL( valueChanged(int)), SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->cbShape, SIGNAL( activated(int)), SIGNAL(sigPleaseUpdatePreview())); +} + + +void KisWdgBlur::setConfiguration(KisFilterConfiguration* config) +{ + QVariant value; + if (config->getProperty("shape", 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/krita/plugins/filters/blur/kis_wdg_blur.h b/krita/plugins/filters/blur/kis_wdg_blur.h new file mode 100644 index 00000000..a1946f80 --- /dev/null +++ b/krita/plugins/filters/blur/kis_wdg_blur.h @@ -0,0 +1,49 @@ +/* + * This file is part of Krita + * + * 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 + public: + KisWdgBlur( KisFilter* nfilter, QWidget * parent, 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/krita/plugins/filters/blur/kritablurfilter.desktop b/krita/plugins/filters/blur/kritablurfilter.desktop new file mode 100644 index 00000000..77984f9e --- /dev/null +++ b/krita/plugins/filters/blur/kritablurfilter.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=Krita/Filter +Type=Service +X-KDE-Library=kritablurfilter +X-Krita-Version=2 diff --git a/krita/plugins/filters/blur/wdgblur.ui b/krita/plugins/filters/blur/wdgblur.ui new file mode 100644 index 00000000..ded12e44 --- /dev/null +++ b/krita/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 + + + + + + layout17 + + + + 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/krita/plugins/filters/bumpmap/Makefile.am b/krita/plugins/filters/bumpmap/Makefile.am new file mode 100644 index 00000000..5018a4e3 --- /dev/null +++ b/krita/plugins/filters/bumpmap/Makefile.am @@ -0,0 +1,18 @@ +kde_services_DATA = kritabumpmapfilter.desktop + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + -I$(srcdir)/../../../../lib/kofficecore \ + $(all_includes) + +kritabumpmap_la_SOURCES = bumpmap.cc wdgbumpmap.ui + +kde_module_LTLIBRARIES = kritabumpmap.la +noinst_HEADERS = bumpmap.h + +kritabumpmap_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritabumpmap_la_LIBADD = ../../../libkritacommon.la + +kritabumpmap_la_METASOURCES = AUTO diff --git a/krita/plugins/filters/bumpmap/bumpmap.cc b/krita/plugins/filters/bumpmap/bumpmap.cc new file mode 100644 index 00000000..833fc655 --- /dev/null +++ b/krita/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 KritaBumpmapFactory; +K_EXPORT_COMPONENT_FACTORY( kritabumpmap, KritaBumpmapFactory( "krita" ) ) + +KritaBumpmap::KritaBumpmap(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(KritaBumpmapFactory::instance()); + + + if (parent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(parent); + manager->add(new KisFilterBumpmap()); + } +} + +KritaBumpmap::~KritaBumpmap() +{ +} + +KisFilterBumpmap::KisFilterBumpmap() : KisFilter(id(), "map", i18n("&Bumpmap...")) +{ +} + +namespace { + void convertRow(KisPaintDevice * orig, Q_UINT8 * row, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_UINT8 * lut, Q_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 QRect& 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; + + Q_INT32 xofs, yofs; /// The x,y offset values + Q_INT32 lx, ly; /* X and Y components of light vector */ + Q_INT32 nz2, nzlz; /* nz^2, nz*lz */ + Q_INT32 background; /* Shade for vertical normals */ + double compensation; /* Background compensation */ + Q_UINT8 lut[256]; /* Look-up table for modes */ + + double azimuth; + double elevation; + Q_INT32 lz, nz; + Q_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 = (Q_INT32)(cos(azimuth) * cos(elevation) * 255.0); + ly = (Q_INT32)(sin(azimuth) * cos(elevation) * 255.0); + + lz = (Q_INT32)(sin(elevation) * 255.0); + + /* Calculate constant Z component of surface normal */ + nz = (Q_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. + QRect 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(); + QValueVector channels = srcCs->channels(); + + // One byte per pixel, converted from the bumpmap layer. + Q_UINT8 * bm_row1 = new Q_UINT8[bmRect.width()]; + Q_UINT8 * bm_row2 = new Q_UINT8[bmRect.width()]; + Q_UINT8 * bm_row3 = new Q_UINT8[bmRect.width()]; + Q_UINT8 * tmp_row; + + // ------------------- Map the bumps + Q_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 Q_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 Q_INT32 xBump = srcIt.x()+xofs; + Q_INT32 nx, ny; + // Calculate surface normal from bumpmap + if (config->tiled || bmRect.left() <= xBump && xBump <= bmRect.right()) { + + Q_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 + Q_INT32 shade; + if ((nx == 0) && (ny == 0)) { + shade = background; + } else { + Q_INT32 ndotl = (nx * lx) + (ny * ly) + nzlz; + + if (ndotl < 0) { + shade = (Q_INT32)(compensation * config->ambient); + } else { + shade = (Q_INT32)(ndotl / sqrt(nx * nx + ny * ny + nz2)); + shade = (Q_INT32)(shade + QMAX(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(QWidget* parent, KisPaintDeviceSP dev) +{ + KisBumpmapConfigWidget * w = new KisBumpmapConfigWidget(this, dev, parent); + + + return w; +} + +KisFilterConfiguration * KisFilterBumpmap::configuration(QWidget * 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 = QString::null; + azimuth = 135.0; + elevation = 45.0; + depth = 3; + xofs = 0; + yofs = 0; + waterlevel = 0; + ambient = 0; + compensate = true; + invert = false; + tiled = true; + type = krita::LINEAR; +} +void KisBumpmapConfiguration::fromXML(const QString & s) +{ + KisFilterConfiguration::fromXML( s ); + + bumpmap = QString::null; + azimuth = 135.0; + elevation = 45.0; + depth = 3; + xofs = 0; + yofs = 0; + waterlevel = 0; + ambient = 0; + compensate = true; + invert = false; + tiled = true; + type = krita::LINEAR; + + QVariant 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(); } + +} + + +QString KisBumpmapConfiguration::toString() +{ + m_properties.clear(); + + //setProperty("bumpmap", QVariant(bumpmap)); + setProperty("azimuth", QVariant(azimuth)); + setProperty("elevation", QVariant(elevation)); + setProperty("depth", QVariant(depth)); + setProperty("xofs", QVariant(xofs)); + setProperty("yofs", QVariant(yofs)); + setProperty("waterlevel", QVariant(waterlevel)); + setProperty("ambient", QVariant(ambient)); + setProperty("compensate", QVariant(compensate)); + setProperty("invert", QVariant(invert)); + setProperty("tiled", QVariant(tiled)); + setProperty("type", QVariant(type)); + + return KisFilterConfiguration::toString(); +} + +KisBumpmapConfigWidget::KisBumpmapConfigWidget(KisFilter *, KisPaintDeviceSP dev, QWidget * parent, const char * name, WFlags f) + : KisFilterConfigWidget(parent, name, f) +{ + m_page = new WdgBumpmap(this); + QHBoxLayout * l = new QHBoxLayout(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, SIGNAL( toggled(bool)), SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->radioSpherical, SIGNAL( toggled(bool)), SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->radioSinusoidal, SIGNAL( toggled(bool)), SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->chkCompensate, SIGNAL( toggled(bool)), SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->chkInvert, SIGNAL( toggled(bool)), SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->chkTiled, SIGNAL( toggled(bool)), SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->dblAzimuth, SIGNAL( valueChanged(int)), SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->dblElevation, SIGNAL( valueChanged(int)), SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->dblDepth, SIGNAL( valueChanged(int)), SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->intXOffset, SIGNAL( valueChanged(int)), SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->intYOffset, SIGNAL( valueChanged(int)), SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->intWaterLevel, SIGNAL( valueChanged(int)), SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->intAmbient, SIGNAL( valueChanged(int)), 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/krita/plugins/filters/bumpmap/bumpmap.h b/krita/plugins/filters/bumpmap/bumpmap.h new file mode 100644 index 00000000..1813b922 --- /dev/null +++ b/krita/plugins/filters/bumpmap/bumpmap.h @@ -0,0 +1,129 @@ +/* + * This file is part of Krita + * + * 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 krita { + + enum enumBumpmapType { + LINEAR = 0, + SPHERICAL = 1, + SINUSOIDAL = 2 + }; + +} + +using namespace krita; + + + +class KritaBumpmap : public KParts::Plugin +{ +public: + KritaBumpmap(QObject *parent, const char *name, const QStringList &); + virtual ~KritaBumpmap(); +}; + + +/** + * 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 QRect&); + 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(QWidget* parent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration * configuration(QWidget*); + virtual KisFilterConfiguration * configuration(); + +}; + + + +class KisBumpmapConfiguration : public KisFilterConfiguration { + +public: + + KisBumpmapConfiguration(); + virtual void fromXML( const QString& ); + virtual QString toString(); + +public: + + QString bumpmap; + double azimuth; + double elevation; + double depth; + Q_INT32 xofs; + Q_INT32 yofs; + Q_INT32 waterlevel; + Q_INT32 ambient; + bool compensate; + bool invert; + bool tiled; + enumBumpmapType type; + +}; + + +class KisBumpmapConfigWidget : public KisFilterConfigWidget { + + Q_OBJECT + +public: + KisBumpmapConfigWidget(KisFilter * filter, KisPaintDeviceSP dev, QWidget * parent, const char * name = 0, WFlags f = 0 ); + virtual ~KisBumpmapConfigWidget() {}; + + KisBumpmapConfiguration * config(); + void setConfiguration(KisFilterConfiguration * config); + +private: + + WdgBumpmap * m_page; +}; + +#endif diff --git a/krita/plugins/filters/bumpmap/kritabumpmapfilter.desktop b/krita/plugins/filters/bumpmap/kritabumpmapfilter.desktop new file mode 100644 index 00000000..73798519 --- /dev/null +++ b/krita/plugins/filters/bumpmap/kritabumpmapfilter.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=Krita/Filter +Type=Service +X-KDE-Library=kritabumpmap +X-Krita-Version=2 diff --git a/krita/plugins/filters/bumpmap/wdgbumpmap.ui b/krita/plugins/filters/bumpmap/wdgbumpmap.ui new file mode 100644 index 00000000..000b15f6 --- /dev/null +++ b/krita/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/krita/plugins/filters/cimg/.kdev_ignore b/krita/plugins/filters/cimg/.kdev_ignore new file mode 100644 index 00000000..e69de29b diff --git a/krita/plugins/filters/cimg/CImg.h b/krita/plugins/filters/cimg/CImg.h new file mode 100644 index 00000000..23c7e221 --- /dev/null +++ b/krita/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 parent 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 alignment of images when displaying images of different sizes. + Can be '\p c' (centered, which is the default), '\p p' (top alignment) 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 emask = + ((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,emask); + } + 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 + emask = ExposureMask|StructureNotifyMask| + ((events>=2)?ButtonPressMask|KeyPressMask|PointerMotionMask|LeaveWindowMask:0)| + ((events>=3)?ButtonReleaseMask|KeyReleaseMask:0); + XSelectInput(cimg::X11attr().display,window,emask); + 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 contains \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 geometry 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 geometry 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 geometry 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 geometry 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 mask = 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,mask); + 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 masks + - 3 = Using rotation invariant masks + - 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 mask + 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 mask + 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& mask, + const int x0=0,const int y0=0,const int z0=0,const int v0=0, + const tm mask_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 (mask.is_empty()) + throw CImgArgumentException("CImg<%s>::draw_image() : Specified mask image (%u,%u,%u,%u,%p) is empty.", + pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data); + if ((void*)this==(void*)&sprite) return draw_image(CImg(sprite),mask,x0,y0,z0,v0); + if(mask.width!=sprite.width || mask.height!=sprite.height || mask.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(),mask.width,mask.height,mask.depth,mask.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*mask.dimx():0)-(bz?z0*mask.dimx()*mask.dimy():0)- + (bv?v0*mask.dimx()*mask.dimy()*mask.dimz():0), + ssize = mask.dimx()*mask.dimy()*mask.dimz(); + const ti *ptrs = sprite.ptr() + coff; + const tm *ptrm = mask.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,mask,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 mask of the filled region mask, as an output. + \param sigma = tolerance concerning neighborhood values. + \param opacity = opacity of the drawing. + + \return \p region is initialized with the binary mask 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 mask. + /** + The result \p res of the correlation of an image \p img by a mask \p mask is defined to be : + + res(x,y,z) = sum_{i,j,k} img(x+i,y+j,z+k)*mask(i,j,k) + + \param mask = 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& mask,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 (mask.is_empty() || mask.dim!=1) + throw CImgArgumentException("CImg<%s>::get_correlate() : Specified mask (%u,%u,%u,%u,%p) is not scalar.", + pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data); + CImg dest(*this,false); + if (cond && mask.width==mask.height && ((mask.depth==1 && mask.width<=5) || (mask.depth==mask.width && mask.width<=3))) { + // A special optimization is done for 2x2,3x3,4x4,5x5,2x2x2 and 3x3x3 mask (with cond=1) + switch (mask.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,mask); + 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,mask)/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,mask); + 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,mask)/std::sqrt(norm)):0; + } + } break; + default: + case 1: + switch (mask.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,mask); + 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,mask)/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,mask); + 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,mask)/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,mask); + 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,mask)/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,mask); + 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,mask)/std::sqrt(norm)):0; + } + } break; + case 1: dest = mask(0)*(*this); break; + } + } + } else { + // Generic version for other masks + const int cxm=mask.width/2, cym=mask.height/2, czm=mask.depth/2, fxm=cxm-1+(mask.width%2), fym=cym-1+(mask.height%2), fzm=czm-1+(mask.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)*mask(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)*mask(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*mask(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*mask(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 mask + /** + This is the in-place version of get_correlate. + \see get_correlate + **/ + template CImg& correlate(const CImg& mask,const unsigned int cond=1,const bool weighted_correl=false) { + return get_correlate(mask,cond,weighted_correl).swap(*this); + } + + //! Return the convolution of the image by a mask + /** + The result \p res of the convolution of an image \p img by a mask \p mask is defined to be : + + res(x,y,z) = sum_{i,j,k} img(x-i,y-j,z-k)*mask(i,j,k) + + \param mask = 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& mask,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 (mask.is_empty() || mask.dim!=1) + throw CImgArgumentException("CImg<%s>::get_convolve() : Specified mask (%u,%u,%u,%u,%p) is not scalar.", + pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data); + CImg dest(*this,false); + if (cond && mask.width==mask.height && ((mask.depth==1 && mask.width<=5) || (mask.depth==mask.width && mask.width<=3))) { // optimized version + switch (mask.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,mask); + 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,mask)/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,mask); + 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,mask)/std::sqrt(norm)):0; + } + } break; + default: + case 1: + switch (mask.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,mask); + 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,mask)/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,mask); + 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,mask)/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,mask); + 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,mask)/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,mask); + 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,mask)/std::sqrt(norm)):0; + } + } break; + case 1: dest = mask(0)*(*this); break; + } + } + } else { // generic version + + const int cxm=mask.width/2, cym=mask.height/2, czm=mask.depth/2, fxm=cxm-1+(mask.width%2), fym=cym-1+(mask.height%2), fzm=czm-1+(mask.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)*mask(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)*mask(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*mask(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*mask(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 mask + /** + This is the in-place version of get_convolve(). + \see get_convolve() + **/ + template CImg& convolve(const CImg& mask,const unsigned int cond=1,const bool weighted_convol=false) { + return get_convolve(mask,cond,weighted_convol).swap(*this); + } + + //! Return the erosion of the image by a structuring element. + template CImg::type> + get_erode(const CImg& mask, const unsigned int cond=1, const bool weighted_erosion=false) const { + typedef typename cimg::largest::type restype; + if (is_empty()) return CImg(); + if (mask.is_empty() || mask.dim!=1) + throw CImgArgumentException("CImg<%s>::get_erosion() : Specified mask (%u,%u,%u,%u,%p) is not a scalar image.", + pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data); + CImg dest(*this,false); + const int cxm=mask.width/2, cym=mask.height/2, czm=mask.depth/2, + fxm=cxm-1+(mask.width%2), fym=cym-1+(mask.height%2), fzm=czm-1+(mask.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 (mask(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 (mask(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=mask(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=mask(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& mask,const unsigned int cond=1,const bool weighted_erosion=false) { + return get_erode(mask,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 mask(3,3,1,1,1); + return get_erode(mask,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& mask, const unsigned int cond=1, const bool weighted_dilatation=false) const { + typedef typename cimg::largest::type restype; + if (is_empty()) return CImg(); + if (mask.is_empty() || mask.dim!=1) + throw CImgArgumentException("CImg<%s>::get_dilate() : Specified mask (%u,%u,%u,%u,%p) is not a scalar image.", + pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data); + CImg dest(*this,false); + const int cxm=mask.width/2, cym=mask.height/2, czm=mask.depth/2, + fxm=cxm-1+(mask.width%2), fym=cym-1+(mask.height%2), fzm=czm-1+(mask.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 (mask(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 (mask(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=mask(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=mask(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& mask,const unsigned int cond=1,const bool weighted_dilatation=false) { + return get_dilate(mask,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 mask(3,3,1,1,1); + return get_dilate(mask,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 geometry. + \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 mask = 0x80, val = 0; + cimg_mapX(res,x) { + if (mask==0x80) val = *(ptrs++); + const unsigned char *col = (unsigned char*)(palette+(val&mask?1:0)); + res(x,y,2) = (T)*(col++); + res(x,y,1) = (T)*(col++); + res(x,y,0) = (T)*(col++); + mask = cimg::ror(mask); + } ptrs+=align; } + } break; + case 4: { // 16 colors + for (int y=res.height-1; y>=0; y--) { + unsigned char mask = 0xF0, val = 0; + cimg_mapX(res,x) { + if (mask==0xF0) val = *(ptrs++); + const unsigned char color = (mask<16)?(val&mask):((val&mask)>>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++); + mask = cimg::ror(mask,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 alignment 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], &mask = res[x/w+256]; + unsigned int xm = x%w; + img(xm,y,0) = img(xm,y,1) = img(xm,y,2) = mask(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 alignment 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 alignment 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 alignment 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/krita/plugins/filters/cimg/Makefile.am b/krita/plugins/filters/cimg/Makefile.am new file mode 100644 index 00000000..a359e5f2 --- /dev/null +++ b/krita/plugins/filters/cimg/Makefile.am @@ -0,0 +1,34 @@ +KDE_CXXFLAGS = $(USE_EXCEPTIONS) -D_GNU_SOURCE + +kde_services_DATA = kritacimg.desktop + +# all_includes must remain last! +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kritacimg_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 = kritacimg.la + +noinst_HEADERS = \ + CImg.h\ + kis_cimg_filter.h\ + kis_cimg_plugin.h\ + kis_cimgconfig_widget.h + +kritacimg_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritacimg_la_LIBADD = ../../../libkritacommon.la + +kritacimg_la_METASOURCES = AUTO + + +KDE_OPTIONS = nofinal diff --git a/krita/plugins/filters/cimg/kis_cimg_filter.cc b/krita/plugins/filters/cimg/kis_cimg_filter.cc new file mode 100644 index 00000000..53f7e3c1 --- /dev/null +++ b/krita/plugins/filters/cimg/kis_cimg_filter.cc @@ -0,0 +1,711 @@ +/* + * This file is part of Krita + * + * 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 QString & 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); +} + + +QString 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 QRect& rect) +{ + Q_UNUSED(dst); + + Q_INT32 width = rect.width(); + Q_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()) { + Q_UINT16* data = reinterpret_cast(it.rawData()); + + Q_INT32 x = it.x() - rect.x(); + Q_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()) { + + QColor color; + cs->toQColor(it.rawData(), &color); + + Q_INT32 x = it.x() - rect.x(); + Q_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()) { + Q_INT32 x = it.x() - rect.x(); + Q_INT32 y = it.y() - rect.y(); + + Q_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()) { + + Q_INT32 x = it.x() - rect.x(); + Q_INT32 y = it.y() - rect.y(); + + QColor color((int)img(x, y, 0), (int)img(x, y, 1), (int)img(x, y, 2)); + + cs->fromQColor(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<>(); + mask = 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 mask"); + if (!file_m) + { + // XXX: Do KDE messagebox + // g_message ("You need to specify an inpainting mask (option '-m') !"); + return false; + } + + const unsigned int dilate = 0; //cimg_option("-dilate",0,"Inpainting mask 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)) + mask = CImg(file_m); + else { + int l=16; std::sscanf(file_m,"block%d",&l); + mask = CImg(img.width/l,img.height/l); + cimg_mapXY(mask,x,y) mask(x,y)=(x+y)%2; + } + mask.resize(img.width,img.height,1,1); + if (dilate) mask.dilate(dilate); + switch (ip_init) { + case 0 : { cimg_mapXYV(img,x,y,k) if (mask(x,y)) img(x,y,k) = 0; } break; + case 1 : { cimg_mapXYV(img,x,y,k) if (mask(x,y)) img(x,y,k) = 255; } break; + case 2 : { cimg_mapXYV(img,x,y,k) if (mask(x,y)) img(x,y,k) = (float)(255*cimg::rand()); } break; + case 3 : break; + case 4 : { + CImg tmask(mask),ntmask(tmask); + CImg_3x3(M,uchar); + CImg_3x3(I,float); + while (CImgStats(ntmask,false).max>0) { + cimg_map3x3(tmask,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; + } + ntmask(x,y) = 0; + } + tmask = ntmask; + } + } break; + default: break; + } + img0=img; + G = CImg<>(img.width,img.height,1,3,0); + CImg_3x3(g,uchar); + CImg_3x3(I,float); + cimg_map3x3(mask,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 geometry"); + 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); + mask = CImg(img.width,img.height,1,1,255); + if (!anchor) mask.resize(w,h,1,1,1); else mask = ~mask.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 geometry"); + //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 (!mask.data || mask(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/krita/plugins/filters/cimg/kis_cimg_filter.h b/krita/plugins/filters/cimg/kis_cimg_filter.h new file mode 100644 index 00000000..da336471 --- /dev/null +++ b/krita/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 QString toString(); + virtual void fromXML(const QString & s); + +public: + + Q_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 QRect&); + 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(QWidget* parent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration * configuration(QWidget*); + 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 mask; + + + +}; + +#endif diff --git a/krita/plugins/filters/cimg/kis_cimg_plugin.cc b/krita/plugins/filters/cimg/kis_cimg_plugin.cc new file mode 100644 index 00000000..569a247e --- /dev/null +++ b/krita/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( kritacimg, KisCImgPluginFactory( "krita" ) ) + +KisCImgPlugin::KisCImgPlugin(QObject *parent, const char *name, const QStringList &) : KParts::Plugin(parent, name) +{ + setInstance(KisCImgPluginFactory::instance()); + + if (parent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(parent); + manager->add(new KisCImgFilter()); + } +} + +KisCImgPlugin::~KisCImgPlugin() +{ +} + diff --git a/krita/plugins/filters/cimg/kis_cimg_plugin.h b/krita/plugins/filters/cimg/kis_cimg_plugin.h new file mode 100644 index 00000000..385ba34f --- /dev/null +++ b/krita/plugins/filters/cimg/kis_cimg_plugin.h @@ -0,0 +1,32 @@ +/* + * This file is part of Krita + * + * 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(QObject *parent, const char *name, const QStringList &); + virtual ~KisCImgPlugin(); +}; + +#endif diff --git a/krita/plugins/filters/cimg/kis_cimgconfig_widget.cc b/krita/plugins/filters/cimg/kis_cimgconfig_widget.cc new file mode 100644 index 00000000..7b98c4cd --- /dev/null +++ b/krita/plugins/filters/cimg/kis_cimgconfig_widget.cc @@ -0,0 +1,94 @@ +/* + * This file is part of Krita + * + * 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 "qlayout.h" +#include "qcheckbox.h" +#include "qpushbutton.h" + +#include "knuminput.h" + +#include "wdg_cimg.h" +#include "kis_cimgconfig_widget.h" +#include "kis_cimg_filter.h" + +KisCImgconfigWidget::KisCImgconfigWidget(KisFilter* nfilter, QWidget * parent, const char * name, WFlags f) + : KisFilterConfigWidget(parent, name, f) +{ + m_page = new WdgCImg(this); + Q_CHECK_PTR(m_page); + + QHBoxLayout * l = new QHBoxLayout(this); + Q_CHECK_PTR(l); + + l->add(m_page); + nfilter->setAutoUpdate(false); + +// connect( m_page->bnRefresh, SIGNAL(clicked()), SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->numDetail, SIGNAL(valueChanged (double)), SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->numGradient, SIGNAL(valueChanged (double)), SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->numTimeStep, SIGNAL(valueChanged (double)), SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->numBlur, SIGNAL(valueChanged (double)), SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->numBlurIterations, SIGNAL(valueChanged (int)), SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->numAngularStep, SIGNAL(valueChanged (double)), SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->numIntegralStep, SIGNAL(valueChanged (double)), SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->numGaussian, SIGNAL(valueChanged (double)), SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->chkLinearInterpolation, SIGNAL(toggled(bool)), SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->chkNormalize, SIGNAL(toggled(bool)), 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/krita/plugins/filters/cimg/kis_cimgconfig_widget.h b/krita/plugins/filters/cimg/kis_cimgconfig_widget.h new file mode 100644 index 00000000..803d4907 --- /dev/null +++ b/krita/plugins/filters/cimg/kis_cimgconfig_widget.h @@ -0,0 +1,49 @@ +/* + * This file is part of Krita + * + * 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 + +public: + + KisCImgconfigWidget(KisFilter* nfilter, QWidget * parent = 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/krita/plugins/filters/cimg/kritacimg.desktop b/krita/plugins/filters/cimg/kritacimg.desktop new file mode 100644 index 00000000..f4498dd7 --- /dev/null +++ b/krita/plugins/filters/cimg/kritacimg.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=Krita/Filter +Type=Service +X-KDE-Library=kritacimg +X-Krita-Version=2 diff --git a/krita/plugins/filters/cimg/wdg_cimg.ui b/krita/plugins/filters/cimg/wdg_cimg.ui new file mode 100644 index 00000000..b4767045 --- /dev/null +++ b/krita/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/krita/plugins/filters/colorify/Colorify.cpp b/krita/plugins/filters/colorify/Colorify.cpp new file mode 100644 index 00000000..d23c6594 --- /dev/null +++ b/krita/plugins/filters/colorify/Colorify.cpp @@ -0,0 +1,122 @@ +/* + * This file is part of Krita + * + * 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 KritaColorifyFactory; +K_EXPORT_COMPONENT_FACTORY( kritacolorify, KritaColorifyFactory( "krita" ) ) + +KritaColorify::KritaColorify(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(KritaColorifyFactory::instance()); + + + kdDebug(41006) << "Colorify Filter plugin. Class: " + << className() + << ", Parent: " + << parent -> className() + << "\n"; + + if (parent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(parent); + manager->add(new KisColorify()); + } +} + +KritaColorify::~KritaColorify() +{ +} + + + +KisColorify::KisColorify() : KisFilter(id(), "colors", i18n("&Colorify...")) +{ +} + +KisFilterConfigWidget * KisColorify::createConfigurationWidget(QWidget* parent, KisPaintDeviceSP ) +{ + return new KisWdgColorify(this, parent, "configuration of colorify"); +} + +KisFilterConfiguration* KisColorify::configuration(QWidget* 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 QRect& rect) +{ + Q_ASSERT(src != 0); + Q_ASSERT(dst != 0); + + if(config == 0) config = new KisFilterConfiguration("colorify", 1); + + QVariant value; + QColor cTA = (config->getProperty("color", value)) ? value.toColor() : QColor(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(); + Q_UINT8* colorpixel = new Q_UINT8[ cs->pixelSize() ]; + + cs->fromQColor(cTA, colorpixel); + + Q_UINT16 labcTA[4]; + Q_UINT16 lab[4]; + + cs->toLabA16(colorpixel, (Q_UINT8*)labcTA, 1); + + int pixelsProcessed = 0; + setProgressTotalSteps(rect.width() * rect.height()); + + //Q_INT32 pixelsize = cs->pixelSize(); + + while( ! srcIt.isDone() ) + { + if(srcIt.isSelected()) + { + cs->toLabA16(srcIt.oldRawData(), (Q_UINT8*)lab, 1); + labcTA[0] = lab[0]; + cs->fromLabA16((Q_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/krita/plugins/filters/colorify/Colorify.h b/krita/plugins/filters/colorify/Colorify.h new file mode 100644 index 00000000..8ba0e18b --- /dev/null +++ b/krita/plugins/filters/colorify/Colorify.h @@ -0,0 +1,56 @@ +/* + * This file is part of Krita + * + * 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 KritaColorify : public KParts::Plugin +{ +public: + KritaColorify(QObject *parent, const char *name, const QStringList &); + virtual ~KritaColorify(); +}; + + +class KisColorify : public KisFilter { + public: + KisColorify(); + public: + virtual void process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration*, const QRect&); + 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(QWidget* parent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(QWidget*); +}; + +#endif diff --git a/krita/plugins/filters/colorify/KisWdgColorify.cpp b/krita/plugins/filters/colorify/KisWdgColorify.cpp new file mode 100644 index 00000000..4ee48444 --- /dev/null +++ b/krita/plugins/filters/colorify/KisWdgColorify.cpp @@ -0,0 +1,50 @@ +/* + * This file is part of Krita + * + * 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, QWidget * parent, const char * name) : KisFilterConfigWidget ( parent, name ) +{ + QGridLayout *widgetLayout = new QGridLayout(this, 1, 1); + m_widget = new WdgColorifyBase(this); + widgetLayout -> addWidget(m_widget,0,0); + connect( m_widget->colorTarget, SIGNAL( changed(const QColor&)), SIGNAL(sigPleaseUpdatePreview())); +} + +void KisWdgColorify::setConfiguration(KisFilterConfiguration* config) +{ + QVariant value; + if(config->getProperty("color", value)) + { + m_widget->colorTarget->setColor( value.toColor() ); + } +} + +#include "KisWdgColorify.moc" diff --git a/krita/plugins/filters/colorify/KisWdgColorify.h b/krita/plugins/filters/colorify/KisWdgColorify.h new file mode 100644 index 00000000..b4101f06 --- /dev/null +++ b/krita/plugins/filters/colorify/KisWdgColorify.h @@ -0,0 +1,44 @@ +/* + * This file is part of Krita + * + * 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 + public: + KisWdgColorify( KisFilter* nfilter, QWidget * parent, const char * name); + inline WdgColorifyBase* widget() { return m_widget; }; + virtual void setConfiguration(KisFilterConfiguration*); + private: + WdgColorifyBase* m_widget; +}; + +#endif diff --git a/krita/plugins/filters/colorify/Makefile.am b/krita/plugins/filters/colorify/Makefile.am new file mode 100644 index 00000000..4fbd0479 --- /dev/null +++ b/krita/plugins/filters/colorify/Makefile.am @@ -0,0 +1,22 @@ +kritarcdir = $(kde_datadir)/krita/kritaplugins + +kde_services_DATA = kritacolorifyfilter.desktop + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + + + +kde_module_LTLIBRARIES = kritacolorify.la + + +kritacolorify_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritacolorify_la_LIBADD = ../../../libkritacommon.la + +METASOURCES = AUTO +kritacolorify_la_SOURCES = Colorify.cpp KisWdgColorify.cpp\ + WdgColorifyBase.ui diff --git a/krita/plugins/filters/colorify/WdgColorifyBase.ui b/krita/plugins/filters/colorify/WdgColorifyBase.ui new file mode 100644 index 00000000..e8387c64 --- /dev/null +++ b/krita/plugins/filters/colorify/WdgColorifyBase.ui @@ -0,0 +1,97 @@ + +WdgColorifyBase + + + WdgColorifyBase + + + + 0 + 0 + 133 + 63 + + + + + unnamed + + + 0 + + + + spacer2 + + + Horizontal + + + Expanding + + + + 61 + 20 + + + + + + layout1 + + + + unnamed + + + + textLabel1 + + + Color: + + + + + colorTarget + + + + + + + 255 + 255 + 255 + + + + + + + + spacer1 + + + Vertical + + + Expanding + + + + 20 + 50 + + + + + + + + + + kcolorbutton.h + + diff --git a/krita/plugins/filters/colorify/kritacolorifyfilter.desktop b/krita/plugins/filters/colorify/kritacolorifyfilter.desktop new file mode 100644 index 00000000..3b8f9b56 --- /dev/null +++ b/krita/plugins/filters/colorify/kritacolorifyfilter.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=Krita/Filter +Type=Service +X-KDE-Library=kritacolorify +X-Krita-Version=2 diff --git a/krita/plugins/filters/colors/Makefile.am b/krita/plugins/filters/colors/Makefile.am new file mode 100644 index 00000000..bbac0895 --- /dev/null +++ b/krita/plugins/filters/colors/Makefile.am @@ -0,0 +1,20 @@ +kritarcdir = $(kde_datadir)/krita/kritaplugins + +kde_services_DATA = kritaextensioncolorsfilters.desktop + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kritaextensioncolorsfilters_la_SOURCES = colors.cc kis_minmax_filters.cc kis_color_to_alpha.cc wdgcolortoalphabase.ui kis_wdg_color_to_alpha.cc + +kde_module_LTLIBRARIES = kritaextensioncolorsfilters.la +noinst_HEADERS = colors.h + +kritaextensioncolorsfilters_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritaextensioncolorsfilters_la_LIBADD = ../../../libkritacommon.la + +METASOURCES = AUTO diff --git a/krita/plugins/filters/colors/colors.cc b/krita/plugins/filters/colors/colors.cc new file mode 100644 index 00000000..b0a8bcc7 --- /dev/null +++ b/krita/plugins/filters/colors/colors.cc @@ -0,0 +1,53 @@ +/* + * This file is part of Krita + * + * 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 KritaExtensionsColorsFactory; +K_EXPORT_COMPONENT_FACTORY( kritaextensioncolorsfilters, KritaExtensionsColorsFactory( "krita" ) ) + +KritaExtensionsColors::KritaExtensionsColors(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(KritaExtensionsColorsFactory::instance()); + + + kdDebug(41006) << "Extensions Colors Filter plugin. Class: " + << className() + << ", Parent: " + << parent -> className() + << "\n"; + + if (parent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(parent); + manager->add(new KisFilterMax()); + manager->add(new KisFilterMin()); + manager->add(new KisFilterColorToAlpha()); + } +} + +KritaExtensionsColors::~KritaExtensionsColors() +{ +} diff --git a/krita/plugins/filters/colors/colors.h b/krita/plugins/filters/colors/colors.h new file mode 100644 index 00000000..169ae83d --- /dev/null +++ b/krita/plugins/filters/colors/colors.h @@ -0,0 +1,37 @@ +/* + * This file is part of Krita + * + * 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 KritaExtensionsColors : public KParts::Plugin +{ +public: + KritaExtensionsColors(QObject *parent, const char *name, const QStringList &); + virtual ~KritaExtensionsColors(); +}; + +#endif diff --git a/krita/plugins/filters/colors/kis_color_to_alpha.cc b/krita/plugins/filters/colors/kis_color_to_alpha.cc new file mode 100644 index 00000000..f4547a28 --- /dev/null +++ b/krita/plugins/filters/colors/kis_color_to_alpha.cc @@ -0,0 +1,95 @@ +/* + * This file is part of Krita + * + * 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(QWidget* parent, KisPaintDeviceSP ) +{ + return new KisWdgColorToAlpha(this, parent, "configuration of color to alpha"); +} + +KisFilterConfiguration* KisFilterColorToAlpha::configuration(QWidget* 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 QRect& rect) +{ + Q_ASSERT(src != 0); + Q_ASSERT(dst != 0); + + if(config == 0) config = new KisFilterConfiguration("colortoalpha", 1); + + QVariant value; + QColor cTA = (config->getProperty("targetcolor", value)) ? value.toColor() : QColor(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(); + Q_INT32 pixelsize = cs->pixelSize(); + + Q_UINT8* color = new Q_UINT8[pixelsize]; + cs->fromQColor(cTA, color); + + while( ! srcIt.isDone() ) + { + if(srcIt.isSelected()) + { + Q_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/krita/plugins/filters/colors/kis_color_to_alpha.h b/krita/plugins/filters/colors/kis_color_to_alpha.h new file mode 100644 index 00000000..1f9c8a08 --- /dev/null +++ b/krita/plugins/filters/colors/kis_color_to_alpha.h @@ -0,0 +1,47 @@ +/* + * This file is part of Krita + * + * 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 QRect&); + 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(QWidget* parent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(QWidget*); +}; + + +#endif diff --git a/krita/plugins/filters/colors/kis_minmax_filters.cc b/krita/plugins/filters/colors/kis_minmax_filters.cc new file mode 100644 index 00000000..3e6fa197 --- /dev/null +++ b/krita/plugins/filters/colors/kis_minmax_filters.cc @@ -0,0 +1,162 @@ +/* + * This file is part of Krita + * + * 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 Q_UINT8* , Q_UINT8* , uint ); + +template +void maximize(const Q_UINT8* s, Q_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 Q_UINT8* s, Q_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 QRect& 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(); + Q_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 QRect& 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(); + Q_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/krita/plugins/filters/colors/kis_minmax_filters.h b/krita/plugins/filters/colors/kis_minmax_filters.h new file mode 100644 index 00000000..1d8300fc --- /dev/null +++ b/krita/plugins/filters/colors/kis_minmax_filters.h @@ -0,0 +1,56 @@ +/* + * This file is part of Krita + * + * 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 QRect&); + 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 QRect&); + 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/krita/plugins/filters/colors/kis_wdg_color_to_alpha.cc b/krita/plugins/filters/colors/kis_wdg_color_to_alpha.cc new file mode 100644 index 00000000..fd37487e --- /dev/null +++ b/krita/plugins/filters/colors/kis_wdg_color_to_alpha.cc @@ -0,0 +1,55 @@ +/* + * This file is part of Krita + * + * 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, QWidget * parent, const char * name) : KisFilterConfigWidget ( parent, name ) +{ + QGridLayout *widgetLayout = new QGridLayout(this, 1, 1); + m_widget = new WdgColorToAlphaBase(this); + widgetLayout -> addWidget(m_widget,0,0); + connect( m_widget->colorTarget, SIGNAL( changed(const QColor&)), SIGNAL(sigPleaseUpdatePreview())); + connect( m_widget->intThreshold, SIGNAL( valueChanged ( int value) ), SIGNAL(sigPleaseUpdatePreview())); +} + +void KisWdgColorToAlpha::setConfiguration(KisFilterConfiguration* config) +{ + QVariant 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/krita/plugins/filters/colors/kis_wdg_color_to_alpha.h b/krita/plugins/filters/colors/kis_wdg_color_to_alpha.h new file mode 100644 index 00000000..e3350e74 --- /dev/null +++ b/krita/plugins/filters/colors/kis_wdg_color_to_alpha.h @@ -0,0 +1,44 @@ +/* + * This file is part of Krita + * + * 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 + public: + KisWdgColorToAlpha( KisFilter* nfilter, QWidget * parent, const char * name); + inline WdgColorToAlphaBase* widget() { return m_widget; }; + virtual void setConfiguration(KisFilterConfiguration*); + private: + WdgColorToAlphaBase* m_widget; +}; + +#endif diff --git a/krita/plugins/filters/colors/kritaextensioncolorsfilters.desktop b/krita/plugins/filters/colors/kritaextensioncolorsfilters.desktop new file mode 100644 index 00000000..cf5e9cdc --- /dev/null +++ b/krita/plugins/filters/colors/kritaextensioncolorsfilters.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=Krita/Filter +Type=Service +X-KDE-Library=kritaextensioncolorsfilters +X-Krita-Version=2 diff --git a/krita/plugins/filters/colors/wdgcolortoalphabase.ui b/krita/plugins/filters/colors/wdgcolortoalphabase.ui new file mode 100644 index 00000000..b6cd3145 --- /dev/null +++ b/krita/plugins/filters/colors/wdgcolortoalphabase.ui @@ -0,0 +1,113 @@ + +WdgColorToAlphaBase + + + WdgColorToAlphaBase + + + + 0 + 0 + 133 + 63 + + + + + unnamed + + + 0 + + + + spacer2 + + + Horizontal + + + Expanding + + + + 61 + 20 + + + + + + layout1 + + + + unnamed + + + + textLabel1 + + + Color: + + + + + colorTarget + + + + + + + 255 + 255 + 255 + + + + + + + + intThreshold + + + 255 + + + + + textLabel1_2 + + + Threshold: + + + + + spacer1 + + + Vertical + + + Expanding + + + + 20 + 50 + + + + + + + + + + kcolorbutton.h + + diff --git a/krita/plugins/filters/colorsfilters/Makefile.am b/krita/plugins/filters/colorsfilters/Makefile.am new file mode 100644 index 00000000..28234235 --- /dev/null +++ b/krita/plugins/filters/colorsfilters/Makefile.am @@ -0,0 +1,25 @@ +kde_services_DATA = kritacolorsfilter.desktop + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kritacolorsfilters_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 + +kritacolorsfilters_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritacolorsfilters_la_LIBADD = ../../../libkritacommon.la + +kde_module_LTLIBRARIES = kritacolorsfilters.la + +kritacolorsfilters_la_METASOURCES = AUTO diff --git a/krita/plugins/filters/colorsfilters/colorsfilters.cc b/krita/plugins/filters/colorsfilters/colorsfilters.cc new file mode 100644 index 00000000..e73cf284 --- /dev/null +++ b/krita/plugins/filters/colorsfilters/colorsfilters.cc @@ -0,0 +1,315 @@ +/* + * This file is part of Krita + * + * 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( kritacolorsfilters, ColorsFiltersFactory( "krita" ) ) + +ColorsFilters::ColorsFilters(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(ColorsFiltersFactory::instance()); + + if (parent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(parent); + 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 QRect& 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()); + Q_INT32 pixelsProcessed = 0; + + while( ! iter.isDone() && !cancelRequested()) + { + Q_UINT32 npix=0, maxpix = iter.nConseqPixels(); + Q_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: + { + Q_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 Q_UINT8 *pixels[2] = {iter.oldRawData(), iter.rawData()}; + Q_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 QRect& 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()); + Q_INT32 pixelsProcessed = 0; + + while( ! iter.isDone() && !cancelRequested()) + { + Q_UINT32 npix=0, maxpix = iter.nConseqPixels(); + Q_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: + { + Q_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 Q_UINT8 *pixels[2] = {iter.oldRawData(), iter.rawData()}; + Q_UINT8 weights[2] = {MAX_SELECTED - selectedness, selectedness}; + src->colorSpace()->mixColors(pixels, weights, 2, iter.rawData()); + ++iter; + pixelsProcessed++; + break; + } + setProgress(pixelsProcessed); + } + setProgressDone(); +} diff --git a/krita/plugins/filters/colorsfilters/colorsfilters.h b/krita/plugins/filters/colorsfilters/colorsfilters.h new file mode 100644 index 00000000..79c467fd --- /dev/null +++ b/krita/plugins/filters/colorsfilters/colorsfilters.h @@ -0,0 +1,73 @@ +/* + * This file is part of Krita + * + * 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(QObject *parent, const char *name, const QStringList &); + virtual ~ColorsFilters(); +}; + +class KisAutoContrast : public KisFilter { +public: + KisAutoContrast(); +public: + virtual void process(KisPaintDeviceSP, KisPaintDeviceSP, KisFilterConfiguration* , const QRect&); + 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 QRect&); + 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/krita/plugins/filters/colorsfilters/kis_brightness_contrast_filter.cc b/krita/plugins/filters/colorsfilters/kis_brightness_contrast_filter.cc new file mode 100644 index 00000000..4169f008 --- /dev/null +++ b/krita/plugins/filters/colorsfilters/kis_brightness_contrast_filter.cc @@ -0,0 +1,347 @@ +/* + * This file is part of Krita + * + * 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 (Q_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 QString& s ) +{ + QDomDocument doc; + doc.setContent( s ); + QDomElement e = doc.documentElement(); + QDomNode n = e.firstChild(); + + while (!n.isNull()) { + e = n.toElement(); + if (!e.isNull()) { + if (e.tagName() == "transfer") { + QStringList data = QStringList::split( ",", e.text() ); + QStringList::Iterator start = data.begin(); + QStringList::Iterator end = data.end(); + int i = 0; + for ( QStringList::Iterator it = start; it != end && i < 256; ++it ) { + QString s = *it; + transfer[i] = s.toUShort(); + i++; + } + } + else if (e.tagName() == "curve") { + QStringList data = QStringList::split( ";", e.text() ); + QStringList::Iterator pairStart = data.begin(); + QStringList::Iterator pairEnd = data.end(); + curve.clear(); // XXX QPtrList, sure I won't leak stuff here? + for (QStringList::Iterator it = pairStart; it != pairEnd; ++it) { + QString pair = * it; + if (pair.find(",") > -1) { + QPair *p = new QPair; + 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 - invalidate it + delete m_adjustment; + m_adjustment = 0; +} + +QString KisBrightnessContrastFilterConfiguration::toString() +{ + QDomDocument doc = QDomDocument("filterconfig"); + QDomElement root = doc.createElement( "filterconfig" ); + root.setAttribute( "name", name() ); + root.setAttribute( "version", version() ); + + doc.appendChild( root ); + + QDomElement e = doc.createElement( "transfer" ); + QString sTransfer; + for ( uint i = 0; i < 255 ; ++i ) { + sTransfer += QString::number( transfer[i] ); + sTransfer += ","; + } + QDomText text = doc.createCDATASection(sTransfer); + e.appendChild(text); + root.appendChild(e); + + e = doc.createElement("curve"); + QString sCurve; + QPair * pair; + for ( pair = curve.first(); pair; pair = curve.next() ) { + sCurve += QString::number(pair->first); + sCurve += ","; + sCurve += QString::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(QWidget *parent, KisPaintDeviceSP dev) +{ + return new KisBrightnessContrastConfigWidget(parent, dev); +} + +KisFilterConfiguration* KisBrightnessContrastFilter::configuration(QWidget *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 QRect& 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()); + Q_INT32 pixelsProcessed = 0; + + while( ! iter.isDone() && !cancelRequested()) + { + Q_UINT32 npix=0, maxpix = iter.nConseqPixels(); + Q_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: + { + Q_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 Q_UINT8 *pixels[2] = {iter.oldRawData(), iter.rawData()}; + Q_UINT8 weights[2] = {MAX_SELECTED - selectedness, selectedness}; + src->colorSpace()->mixColors(pixels, weights, 2, iter.rawData()); + ++iter; + pixelsProcessed++; + break; + } + setProgress(pixelsProcessed); + } + + setProgressDone(); +} + +KisBrightnessContrastConfigWidget::KisBrightnessContrastConfigWidget(QWidget * parent, KisPaintDeviceSP dev, const char * name, WFlags f) + : KisFilterConfigWidget(parent, name, f) +{ + int i; + int height; + m_page = new WdgBrightnessContrast(this); + QHBoxLayout * l = new QHBoxLayout(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, Qt::AlignTop); + height = 256; + connect( m_page->kCurve, SIGNAL(modified()), SIGNAL(sigPleaseUpdatePreview())); + + // Create the horizontal gradient label + QPixmap hgradientpix(256, 1); + QPainter hgp(&hgradientpix); + hgp.setPen(QPen::QPen(QColor(0,0,0),1, Qt::SolidLine)); + for( i=0; i<256; ++i ) + { + hgp.setPen(QColor(i,i,i)); + hgp.drawPoint(i, 0); + } + m_page->hgradient->setPixmap(hgradientpix); + + // Create the vertical gradient label + QPixmap vgradientpix(1, 256); + QPainter vgp(&vgradientpix); + vgp.setPen(QPen::QPen(QColor(0,0,0),1, Qt::SolidLine)); + for( i=0; i<256; ++i ) + { + vgp.setPen(QColor(i,i,i)); + vgp.drawPoint(0, 255-i); + } + m_page->vgradient->setPixmap(vgradientpix); + + KisHistogramProducerSP producer = new KisGenericLabHistogramProducer(); + KisHistogram histogram(dev, producer, LINEAR); + QPixmap pix(256, height); + pix.fill(); + QPainter p(&pix); + p.setPen(QPen::QPen(Qt::gray,1, Qt::SolidLine)); + + double highest = (double)histogram.calculations().getHighest(); + Q_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++) + { + Q_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/krita/plugins/filters/colorsfilters/kis_brightness_contrast_filter.h b/krita/plugins/filters/colorsfilters/kis_brightness_contrast_filter.h new file mode 100644 index 00000000..eb2b2080 --- /dev/null +++ b/krita/plugins/filters/colorsfilters/kis_brightness_contrast_filter.h @@ -0,0 +1,84 @@ +/* + * This file is part of Krita + * + * 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 QWidget; +class KisColorAdjustment; + +class KisBrightnessContrastFilterConfiguration : public KisFilterConfiguration { + +public: + + KisBrightnessContrastFilterConfiguration(); + virtual ~KisBrightnessContrastFilterConfiguration(); + virtual void fromXML( const QString& ); + virtual QString toString(); + +public: + Q_UINT16 transfer[256]; + QPtrList > curve; + KisColorAdjustment * m_adjustment; +}; + +/** + * This class affect Intensity Y of the image + */ +class KisBrightnessContrastFilter : public KisFilter +{ + +public: + + KisBrightnessContrastFilter(); + +public: + + virtual KisFilterConfigWidget * createConfigurationWidget(QWidget* parent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration * configuration(QWidget *); + virtual KisFilterConfiguration * configuration() { return new KisBrightnessContrastFilterConfiguration(); }; + virtual void process(KisPaintDeviceSP, KisPaintDeviceSP, KisFilterConfiguration* , const QRect&); + 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(QWidget * parent, KisPaintDeviceSP dev, const char * name = 0, WFlags f = 0 ); + virtual ~KisBrightnessContrastConfigWidget() {}; + + KisBrightnessContrastFilterConfiguration * config(); + void setConfiguration( KisFilterConfiguration * config ); + WdgBrightnessContrast * m_page; +}; + +#endif diff --git a/krita/plugins/filters/colorsfilters/kis_perchannel_filter.cc b/krita/plugins/filters/colorsfilters/kis_perchannel_filter.cc new file mode 100644 index 00000000..75b19a21 --- /dev/null +++ b/krita/plugins/filters/colorsfilters/kis_perchannel_filter.cc @@ -0,0 +1,421 @@ +/* + * This file is part of Krita + * + * 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 QSortedList >[n]; + for(int i=0;i >[nTransfers]; + while (!curvesNode.isNull()) { + QDomElement curvesElement = curvesNode.toElement(); + if (!curvesElement.isNull() && +!curvesElement.text().isEmpty()) { + QStringList data = QStringList::split( ";", +curvesElement.text() ); + QStringList::Iterator pairStart = data.begin(); + QStringList::Iterator pairEnd = data.end(); + for (QStringList::Iterator it = pairStart; it != pairEnd; ++it) { + QString pair = * it; + if (pair.find(",") > -1) { + QPair *p = new QPair; + 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 Q_UINT16[256]; + for(int i = 0; i < 256; ++i) + { + Q_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; +} + +QString KisPerChannelFilterConfiguration::toString() +{ + QDomDocument doc = QDomDocument("filterconfig"); + QDomElement root = doc.createElement( "filterconfig" ); + root.setAttribute( "name", name() ); + root.setAttribute( "version", version() ); + + QDomElement c = doc.createElement("curves"); + c.setAttribute("number", nTransfers); + c.setAttribute("name", "curves"); + for (int i = 0; i < nTransfers; ++i) { + QDomElement t = doc.createElement("curve"); + QPtrList > curve = curves[i]; + QString sCurve; + QPair * pair; + for ( pair = curve.first(); pair; pair = curve.next() ) { + sCurve += QString::number(pair->first); + sCurve += ","; + sCurve += QString::number(pair->second); + sCurve += ";"; + } + QDomText text = doc.createCDATASection(sCurve); + t.appendChild(text); + c.appendChild(t); + } + root.appendChild(c); + + + doc.appendChild( root ); + return doc.toString(); +} + + +KisFilterConfigWidget * KisPerChannelFilter::createConfigurationWidget(QWidget *parent, KisPaintDeviceSP dev) +{ + return new KisPerChannelConfigWidget(parent, dev); +} + +KisFilterConfiguration* KisPerChannelFilter::configuration(QWidget *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 QRect& 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()); + Q_INT32 pixelsProcessed = 0; + + while( ! iter.isDone() && !cancelRequested()) + { + Q_UINT32 npix=0, maxpix = iter.nConseqPixels(); + Q_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: + { + Q_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 Q_UINT8 *pixels[2] = {iter.oldRawData(), iter.rawData()}; + Q_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; + QPixmap pix(256, height); + pix.fill(); + QPainter p(&pix); + p.setPen(QPen::QPen(Qt::gray,1, Qt::SolidLine)); + + m_histogram->setChannel(ch); + + double highest = (double)m_histogram->calculations().getHighest(); + Q_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(QWidget * parent, KisPaintDeviceSP dev, const char * name, WFlags f) + : KisFilterConfigWidget(parent, name, f) +{ + int i; + int height; + m_page = new WdgPerChannel(this); + QHBoxLayout * l = new QHBoxLayout(this); + Q_CHECK_PTR(l); + + m_dev = dev; + m_curves = new QSortedList >[m_dev->colorSpace()->nColorChannels()]; + m_activeCh = 0; + for(unsigned int ch=0; ch colorSpace()->nColorChannels(); ch++) + { + m_curves[ch].append(new QPair(0, 0)); + m_curves[ch].append(new QPair(1, 1)); + } + + l->add(m_page); + height = 256; + connect( m_page->kCurve, SIGNAL(modified()), SIGNAL(sigPleaseUpdatePreview())); + + // Fill in the channel chooser + QValueVector 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, SIGNAL(activated(int)), this, SLOT(setActiveChannel(int))); + + // Create the horizontal gradient label + QPixmap hgradientpix(256, 1); + QPainter hgp(&hgradientpix); + hgp.setPen(QPen::QPen(QColor(0,0,0),1, Qt::SolidLine)); + for( i=0; i<256; ++i ) + { + hgp.setPen(QColor(i,i,i)); + hgp.drawPoint(i, 0); + } + m_page->hgradient->setPixmap(hgradientpix); + + // Create the vertical gradient label + QPixmap vgradientpix(1, 256); + QPainter vgp(&vgradientpix); + vgp.setPen(QPen::QPen(QColor(0,0,0),1, Qt::SolidLine)); + for( i=0; i<256; ++i ) + { + vgp.setPen(QColor(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(); + QPair *p, *inpoint; + inpoint = m_curves[ch].first(); + while(inpoint) + { + p = new QPair(inpoint->first, inpoint->second); + cfg->curves[ch].append(p); + inpoint = m_curves[ch].next(); + } + + for(int i=0; i <256; i++) + { + Q_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(); + QPair *p, *inpoint; + inpoint = cfg->curves[ch].first(); + while(inpoint) + { + p = new QPair(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/krita/plugins/filters/colorsfilters/kis_perchannel_filter.h b/krita/plugins/filters/colorsfilters/kis_perchannel_filter.h new file mode 100644 index 00000000..a34e9aac --- /dev/null +++ b/krita/plugins/filters/colorsfilters/kis_perchannel_filter.h @@ -0,0 +1,99 @@ +/* + * This file is part of Krita + * + * 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 QString& ); + virtual QString toString(); + +public: + QPtrList > *curves; + Q_UINT16 *transfers[256]; + Q_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(QWidget* parent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(QWidget*); + virtual KisFilterConfiguration* configuration() { return new KisPerChannelFilterConfiguration(0); }; + virtual void process(KisPaintDeviceSP, KisPaintDeviceSP, KisFilterConfiguration* , const QRect&); + 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 + +public: + KisPerChannelConfigWidget(QWidget * parent, 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; + QPtrList > *m_curves; + int m_activeCh; +}; + +#endif diff --git a/krita/plugins/filters/colorsfilters/kritacolorsfilter.desktop b/krita/plugins/filters/colorsfilters/kritacolorsfilter.desktop new file mode 100644 index 00000000..e3e7fad9 --- /dev/null +++ b/krita/plugins/filters/colorsfilters/kritacolorsfilter.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=Krita/Filter +Type=Service +X-KDE-Library=kritacolorsfilters +X-Krita-Version=2 diff --git a/krita/plugins/filters/colorsfilters/wdg_brightness_contrast.ui b/krita/plugins/filters/colorsfilters/wdg_brightness_contrast.ui new file mode 100644 index 00000000..bf09239e --- /dev/null +++ b/krita/plugins/filters/colorsfilters/wdg_brightness_contrast.ui @@ -0,0 +1,292 @@ + +WdgBrightnessContrast + + + WdgBrightnessContrast + + + + 0 + 0 + 284 + 346 + + + + + 0 + 0 + 0 + 0 + + + + BrightnessCon + + + + unnamed + + + 0 + + + + layout4 + + + + 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 + + + + + + + layout7 + + + + 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/krita/plugins/filters/colorsfilters/wdg_perchannel.ui b/krita/plugins/filters/colorsfilters/wdg_perchannel.ui new file mode 100644 index 00000000..464e97fd --- /dev/null +++ b/krita/plugins/filters/colorsfilters/wdg_perchannel.ui @@ -0,0 +1,190 @@ + +WdgPerChannel + + + WdgPerChannel + + + + 0 + 0 + 609 + 698 + + + + BrightnessCon + + + + unnamed + + + 0 + + + + layout4 + + + + unnamed + + + + textLabel1 + + + Channel: + + + + + cmbChannel + + + + + + + layout8 + + + + 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/krita/plugins/filters/convolutionfilters/Makefile.am b/krita/plugins/filters/convolutionfilters/Makefile.am new file mode 100644 index 00000000..0e55cfb4 --- /dev/null +++ b/krita/plugins/filters/convolutionfilters/Makefile.am @@ -0,0 +1,27 @@ +kde_services_DATA = kritaconvolutionfilters.desktop + +INCLUDES = \ + -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../ui \ + -I../../../ui/ \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = kritaconvolutionfilters.la + +kritaconvolutionfilters_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 + +kritaconvolutionfilters_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritaconvolutionfilters_la_LIBADD = ../../../libkritacommon.la + +kritaconvolutionfilters_la_METASOURCES = AUTO diff --git a/krita/plugins/filters/convolutionfilters/convolutionfilters.cc b/krita/plugins/filters/convolutionfilters/convolutionfilters.cc new file mode 100644 index 00000000..1eaf788d --- /dev/null +++ b/krita/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( Q_INT32 i0, Q_INT32 i1, Q_INT32 i2, + Q_INT32 i3, Q_INT32 i4, Q_INT32 i5, + Q_INT32 i6, Q_INT32 i7, Q_INT32 i8, + Q_INT32 factor, Q_INT32 offset ) +{ + KisKernelSP kernel = new KisKernel(); + kernel->width = 3; + kernel->height = 3; + + kernel->factor = factor; + kernel->offset = offset; + + kernel->data = new Q_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 KritaConvolutionFiltersFactory; +K_EXPORT_COMPONENT_FACTORY( kritaconvolutionfilters, KritaConvolutionFiltersFactory( "krita" ) ) + +KritaConvolutionFilters::KritaConvolutionFilters(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(KritaConvolutionFiltersFactory::instance()); + + if (parent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(parent); + 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()); + } +} + +KritaConvolutionFilters::~KritaConvolutionFilters() +{ +} + +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("Emboss Horizontal && 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("Emboss Vertical Only")) +{ + m_matrix = createKernel( 0, -1, 0 , 0, 2, 0 , 0, -1, 0, 1, 127); +} + +KisEmbossHorizontalFilter::KisEmbossHorizontalFilter() : + KisConvolutionConstFilter(id(), "emboss", i18n("Emboss 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/krita/plugins/filters/convolutionfilters/convolutionfilters.h b/krita/plugins/filters/convolutionfilters/convolutionfilters.h new file mode 100644 index 00000000..15a23c2b --- /dev/null +++ b/krita/plugins/filters/convolutionfilters/convolutionfilters.h @@ -0,0 +1,152 @@ +/* + * This file is part of Krita + * + * 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("Emboss Horizontal & Vertical")); }; + virtual bool supportsPainting() { return false; } + +}; + +class KisEmbossVerticalFilter : public KisConvolutionConstFilter { +public: + KisEmbossVerticalFilter(); +public: + static inline KisID id() { return KisID("emboss vertical only", i18n("Emboss Vertical Only")); }; + virtual bool supportsPainting() { return false; } + +}; + +class KisEmbossHorizontalFilter : public KisConvolutionConstFilter { +public: + KisEmbossHorizontalFilter(); +public: + static inline KisID id() { return KisID("emboss horizontal only", i18n("Emboss 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 KritaConvolutionFilters : public KParts::Plugin +{ +public: + KritaConvolutionFilters(QObject *parent, const char *name, const QStringList &); + virtual ~KritaConvolutionFilters(); +}; + +#endif diff --git a/krita/plugins/filters/convolutionfilters/kis_convolution_filter.cc b/krita/plugins/filters/convolutionfilters/kis_convolution_filter.cc new file mode 100644 index 00000000..dc86b8d2 --- /dev/null +++ b/krita/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 "qdom.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 QString & s) +{ + m_matrix = new KisKernel(); + + QDomDocument doc; + doc.setContent( s ); + QDomElement e = doc.documentElement(); + QDomNode n = e.firstChild(); + + m_name = e.attribute("name"); + m_version = e.attribute("version").toInt(); + + QDomElement matrix = n.toElement(); + m_matrix->width = QString( matrix.attribute( "width" ) ).toInt(); + m_matrix->height = QString( matrix.attribute( "height" ) ).toInt(); + m_matrix->offset = QString( matrix.attribute( "offset" ) ).toInt(); + m_matrix->factor = QString( matrix.attribute( "factor" ) ).toInt(); + + m_matrix->data = new Q_INT32[m_matrix->width * m_matrix->height]; + + QStringList data = QStringList::split( ",", e.text() ); + QStringList::Iterator start = data.begin(); + QStringList::Iterator end = data.end(); + int i = 0; + for ( QStringList::Iterator it = start; it != end; ++it ) { + QString s = *it; + m_matrix->data[i] = s.toInt(); + i++; + } +} + +QString KisConvolutionConfiguration::toString() +{ + QDomDocument doc = QDomDocument("filterconfig"); + QDomElement root = doc.createElement( "filterconfig" ); + root.setAttribute( "name", name() ); + root.setAttribute( "version", version() ); + + doc.appendChild( root ); + + QDomElement 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 ); + + QString data; + + for ( uint i = 0; i < m_matrix->width * m_matrix->height; ++i ) { + data += QString::number( m_matrix->data[i] ); + data += ","; + } + + QDomText text = doc.createCDATASection(data); + e.appendChild(text); + root.appendChild(e); + + return doc.toString(); + +} + +void KisConvolutionFilter::process(KisPaintDeviceSP src, + KisPaintDeviceSP dst, + KisFilterConfiguration* configuration, + const QRect& 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 QMAX(kernel->width / 2, kernel->height / 2); +} + +KisFilterConfiguration* KisConvolutionConstFilter::configuration(QWidget*) +{ + return new KisConvolutionConfiguration( id().id(), m_matrix, m_channelFlags); +} + +#include "kis_convolution_filter.moc" diff --git a/krita/plugins/filters/convolutionfilters/kis_convolution_filter.h b/krita/plugins/filters/convolutionfilters/kis_convolution_filter.h new file mode 100644 index 00000000..f33ddc27 --- /dev/null +++ b/krita/plugins/filters/convolutionfilters/kis_convolution_filter.h @@ -0,0 +1,98 @@ +/* + * This file is part of Krita + * + * 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 QString & name, KisKernel * matrix, + KisChannelInfo::enumChannelFlags channelFlags = KisChannelInfo::FLAG_COLOR_AND_ALPHA) + : KisFilterConfiguration( name, 1 ) + , m_matrix(matrix) + , m_channelFlags(channelFlags) + {}; + + void fromXML(const QString & s); + QString 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 + +public: + + KisConvolutionFilter(const KisID& id, const QString & category, const QString & entry) + : KisFilter( id, category, entry ) + {}; + +public: + + virtual void process(KisPaintDeviceSP,KisPaintDeviceSP, KisFilterConfiguration* , const QRect&); + 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 QString & category, const QString & entry) + : KisConvolutionFilter(id, category, entry) + { + m_channelFlags = KisChannelInfo::FLAG_COLOR_AND_ALPHA; + }; + + virtual ~KisConvolutionConstFilter() {}; + +public: + + virtual KisFilterConfiguration * configuration(QWidget*); + virtual KisFilterConfiguration * configuration() { return configuration(0); }; + +protected: + + KisKernelSP m_matrix; + KisChannelInfo::enumChannelFlags m_channelFlags; +}; + +#endif diff --git a/krita/plugins/filters/convolutionfilters/kis_custom_convolution_filter.cc b/krita/plugins/filters/convolutionfilters/kis_custom_convolution_filter.cc new file mode 100644 index 00000000..06998e3c --- /dev/null +++ b/krita/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(QWidget* parent, KisPaintDeviceSP) +{ + KisCustomConvolutionFilterConfigurationWidget* ccfcw = new KisCustomConvolutionFilterConfigurationWidget(this,parent, "custom convolution config widget"); + Q_CHECK_PTR(ccfcw); + return ccfcw; +} + +KisFilterConfiguration * KisCustomConvolutionFilter::configuration(QWidget* 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 Q_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 Q_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/krita/plugins/filters/convolutionfilters/kis_custom_convolution_filter.h b/krita/plugins/filters/convolutionfilters/kis_custom_convolution_filter.h new file mode 100644 index 00000000..39845cd5 --- /dev/null +++ b/krita/plugins/filters/convolutionfilters/kis_custom_convolution_filter.h @@ -0,0 +1,54 @@ +/* + * This file is part of Krita + * + * 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 QWidget; + +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(QWidget* parent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration * configuration(QWidget*); + virtual KisFilterConfiguration * configuration() { return configuration(0); }; +protected: + virtual KisKernelSP matrix() { return m_matrix; }; +private: + KisKernelSP m_matrix; +}; + + + + +#endif diff --git a/krita/plugins/filters/convolutionfilters/kis_custom_convolution_filter_configuration_base_widget.ui b/krita/plugins/filters/convolutionfilters/kis_custom_convolution_filter_configuration_base_widget.ui new file mode 100644 index 00000000..5c94934e --- /dev/null +++ b/krita/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 + + + + layout5 + + + + unnamed + + + + matrixWidget + + + + + layout4 + + + + unnamed + + + + textLabelFactor + + + Factor: + + + + + spinBoxFactor + + + 1 + + + 1 + + + + + spacer1 + + + Horizontal + + + Expanding + + + + 21 + 20 + + + + + + + + layout3 + + + + 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/krita/plugins/filters/convolutionfilters/kis_custom_convolution_filter_configuration_widget.cc b/krita/plugins/filters/convolutionfilters/kis_custom_convolution_filter_configuration_widget.cc new file mode 100644 index 00000000..51ad5e62 --- /dev/null +++ b/krita/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*/, QWidget * parent, const char * name) + : KisFilterConfigWidget ( parent, name ) +{ + QGridLayout *widgetLayout = new QGridLayout(this, 2, 1); + Q_CHECK_PTR(widgetLayout); + +// QPushButton *bnRefresh = new QPushButton(i18n("Refresh Preview"), this, "bnrefresh"); +// Q_CHECK_PTR(bnRefresh); + +// QSpacerItem *spacer = new QSpacerItem(100, 30, QSizePolicy::Expanding, QSizePolicy::Minimum); +// Q_CHECK_PTR(spacer); + +// widgetLayout->addWidget(bnRefresh, 0, 0); +// widgetLayout->addItem(spacer, 0, 1); + + m_ccfcws = new KisCustomConvolutionFilterConfigurationBaseWidget((QWidget*)this); + Q_CHECK_PTR(m_ccfcws); + + widgetLayout->addMultiCellWidget(m_ccfcws, 1, 1, 0, 1); + +// connect( bnRefresh, SIGNAL(clicked()), nfilter, SLOT(refreshPreview())); + connect( m_ccfcws->matrixWidget, SIGNAL(valueChanged()), SIGNAL(sigPleaseUpdatePreview())); + connect( m_ccfcws->spinBoxFactor, SIGNAL(valueChanged(int)), SIGNAL(sigPleaseUpdatePreview())); + connect( m_ccfcws->spinBoxOffset, SIGNAL(valueChanged(int)), 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/krita/plugins/filters/convolutionfilters/kis_custom_convolution_filter_configuration_widget.h b/krita/plugins/filters/convolutionfilters/kis_custom_convolution_filter_configuration_widget.h new file mode 100644 index 00000000..40389554 --- /dev/null +++ b/krita/plugins/filters/convolutionfilters/kis_custom_convolution_filter_configuration_widget.h @@ -0,0 +1,45 @@ +/* + * 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 QWidget; +class KisCustomConvolutionFilterConfigurationBaseWidget; +class KisMatrixWidget; +class KisFilter; + +class KisCustomConvolutionFilterConfigurationWidget : public KisFilterConfigWidget +{ + + Q_OBJECT + +public: + + KisCustomConvolutionFilterConfigurationWidget( KisFilter* nfilter, QWidget * parent, const char * name); + inline KisCustomConvolutionFilterConfigurationBaseWidget* matrixWidget() { return m_ccfcws; }; + void setConfiguration(KisFilterConfiguration * config); + +private: + + KisCustomConvolutionFilterConfigurationBaseWidget* m_ccfcws; +}; + +#endif diff --git a/krita/plugins/filters/convolutionfilters/kritaconvolutionfilters.desktop b/krita/plugins/filters/convolutionfilters/kritaconvolutionfilters.desktop new file mode 100644 index 00000000..b98e8a22 --- /dev/null +++ b/krita/plugins/filters/convolutionfilters/kritaconvolutionfilters.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=Krita/Filter +Type=Service +X-KDE-Library=kritaconvolutionfilters +X-Krita-Version=2 diff --git a/krita/plugins/filters/cubismfilter/Makefile.am b/krita/plugins/filters/cubismfilter/Makefile.am new file mode 100644 index 00000000..a6fdd290 --- /dev/null +++ b/krita/plugins/filters/cubismfilter/Makefile.am @@ -0,0 +1,24 @@ +kde_services_DATA = kritacubismfilter.desktop + +INCLUDES = \ + -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = kritacubismfilter.la + +kritacubismfilter_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 + +kritacubismfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritacubismfilter_la_LIBADD = ../../../libkritacommon.la + +kritacubismfilter_la_METASOURCES = AUTO diff --git a/krita/plugins/filters/cubismfilter/kis_cubism_filter.cc b/krita/plugins/filters/cubismfilter/kis_cubism_filter.cc new file mode 100644 index 00000000..aa374419 --- /dev/null +++ b/krita/plugins/filters/cubismfilter/kis_cubism_filter.cc @@ -0,0 +1,453 @@ +/* + * This file is part of Krita + * + * 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 QRect& rect) +{ + Q_ASSERT(src); + Q_ASSERT(dst); + Q_ASSERT(configuration); + + //read the filter configuration values from the KisFilterConfiguration object + Q_UINT32 tileSize = ((KisCubismFilterConfiguration*)configuration)->tileSize(); + Q_UINT32 tileSaturation = ((KisCubismFilterConfiguration*)configuration)->tileSaturation(); + + KisColorSpace * cs = src->colorSpace(); + QString 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, QRect(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 (Q_INT32 count, Q_INT32* indices) +{ + Q_INT32 index1, index2; + Q_INT32 tmp; + + //initialize random number generator with time + srand(static_cast(time(0))); + + for (Q_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; + } +} + +Q_INT32 KisCubismFilter::randomIntNumber(Q_INT32 lowestNumber, Q_INT32 highestNumber) +{ + if(lowestNumber > highestNumber) + { + Q_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 (Q_INT32 x1, Q_INT32 y1, Q_INT32 x2, Q_INT32 y2, Q_INT32 offset, Q_INT32* min, Q_INT32* max, Q_INT32 xmin, Q_INT32 xmax) +{ + if (y1 > y2) + { + Q_INT32 tmp = y2; y2 = y1; y1 = tmp; + tmp = x2; x2 = x1; x1 = tmp; + } + Q_INT32 ydiff = (y2 - y1); + + if (ydiff) + { + double xinc = static_cast(x2 - x1) / static_cast(ydiff); + double xstart = x1 + 0.5 * xinc; + for (Q_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 Q_UINT8* col, Q_UINT8* /*s*/, QRect rect) +{ + Q_INT32 val; + Q_INT32 alpha; + Q_UINT8 buf[4]; + Q_INT32 x, y; + double xx, yy; + double vec[2]; + Q_INT32 x1 = rect.left(), y1 = rect.top(), x2 = rect.right(), y2 = rect.bottom(); +// Q_INT32 selWidth, selHeight; + Q_INT32 *vals, *valsIter, *valsEnd; + Q_INT32 b; + Q_INT32 xs, ys, xe, ye; + + + Q_INT32 sx = (Q_INT32) (*poly)[0].x(); + Q_INT32 sy = (Q_INT32) (*poly)[0].y(); + Q_INT32 ex = (Q_INT32) (*poly)[1].x(); + Q_INT32 ey = (Q_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; + } + + Q_INT32 pixelSize = src->pixelSize(); + //get the extents of the polygon + double dMinX, dMinY, dMaxX, dMaxY; + poly->extents (dMinX, dMinY, dMaxX, dMaxY); + Q_INT32 minX = static_cast(dMinX); + Q_INT32 minY = static_cast(dMinY); + Q_INT32 maxX = static_cast(dMaxX); + Q_INT32 maxY = static_cast(dMaxY); + Q_INT32 sizeX = (maxX - minX) * SUPERSAMPLE; + Q_INT32 sizeY = (maxY - minY) * SUPERSAMPLE; + + Q_INT32 *minScanlines = new Q_INT32[sizeY]; + Q_INT32 *minScanlinesIter = minScanlines; + Q_INT32 *maxScanlines = new Q_INT32[sizeY]; + Q_INT32 *maxScanlinesIter = maxScanlines; + + for (Q_INT32 i = 0; i < sizeY; i++) + { + minScanlines[i] = maxX * SUPERSAMPLE; + maxScanlines[i] = minX * SUPERSAMPLE; + } + + if ( poly->numberOfPoints() ) + { + Q_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 Q_INT32[sizeX]; +// x1 = minX; x2 = maxX; y1 = minY; y2 = maxY; + for (Q_INT32 i = 0; i < sizeY; i++, minScanlinesIter++, maxScanlinesIter++) + { + if (! (i % SUPERSAMPLE)) + { + memset (vals, 0, sizeof( Q_INT32 ) * sizeX); + } + + yy = static_cast(i) / static_cast(SUPERSAMPLE) + minY; + + for (Q_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 (Q_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 Q_UINT8* srcPixel = srcIt.oldRawData(); +// memcpy( buf, srcPixel, sizeof(Q_UINT8) * pixelSize ); + src->readBytes(buf, x, y, 1, 1); + #ifndef USE_READABLE_BUT_SLOW_CODE + Q_UINT8 *bufIter = buf; + const Q_UINT8 *colIter = col; + Q_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 QRect& rect, Q_UINT32 tileSize, Q_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 ); + Q_INT32 depth = src->colorSpace()->nColorChannels(); + while( ! dstIt.isDone() ) + { + for( Q_INT32 i = 0; i < depth; i++) + { + dstIt.rawData()[i] = 0; + } + ++dstIt; + } + + //compute number of rows and columns + Q_INT32 cols = ( rect.width() + tileSize - 1) / tileSize; + Q_INT32 rows = ( rect.height() + tileSize - 1) / tileSize; + Q_INT32 numTiles = (rows + 1) * (cols + 1); + + setProgressTotalSteps(numTiles); + setProgressStage(i18n("Applying cubism filter..."),0); + + Q_INT32* randomIndices = new Q_INT32[numTiles]; + for (Q_INT32 i = 0; i < numTiles; i++) + { + randomIndices[i] = i; + } + randomizeIndices (numTiles, randomIndices); + + Q_INT32 count = 0; + Q_INT32 i, j, ix, iy; + double x, y, width, height, theta; + KisPolygon *poly = new KisPolygon(); + Q_INT32 pixelSize = src->pixelSize(); + const Q_UINT8 *srcPixel /*= new Q_UINT8[ pixelSize ]*/; + Q_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 = (Q_INT32) CLAMP (x, rect.x(), rect.x() + rect.width() - 1); + iy = (Q_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(QWidget* parent, 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(parent, id().id().ascii(), id().id().ascii(), param ); +} + +KisFilterConfiguration* KisCubismFilter::configuration(QWidget* 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/krita/plugins/filters/cubismfilter/kis_cubism_filter.h b/krita/plugins/filters/cubismfilter/kis_cubism_filter.h new file mode 100644 index 00000000..bd611d38 --- /dev/null +++ b/krita/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(Q_UINT32 tileSize, Q_UINT32 tileSaturation) + : KisFilterConfiguration( "cubism", 1 ) + , m_tileSize(tileSize) + , m_tileSaturation(tileSaturation) + { + setProperty("tileSize", tileSize); + setProperty("tileSaturation", tileSaturation); + }; +public: + inline Q_UINT32 tileSize() { return getInt("tileSize"); }; + inline Q_UINT32 tileSaturation() {return getInt("tileSaturation"); }; +private: + Q_UINT32 m_tileSize; + Q_UINT32 m_tileSaturation; +}; + +class KisCubismFilter : public KisFilter +{ +public: + KisCubismFilter(); +public: + virtual void process(KisPaintDeviceSP,KisPaintDeviceSP, KisFilterConfiguration* , const QRect&); + 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(QWidget* parent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(QWidget*); + 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 (Q_INT32 count, Q_INT32* indices); + Q_INT32 randomIntNumber(Q_INT32 lowestNumber, Q_INT32 highestNumber); + double randomDoubleNumber(double lowestNumber, double highestNumber); + double calcAlphaBlend(double *vec, double oneOverDist, double x, double y); + void convertSegment(Q_INT32 x1, Q_INT32 y1, Q_INT32 x2, Q_INT32 y2, Q_INT32 offset, Q_INT32* min, Q_INT32* max, Q_INT32 xmin, Q_INT32 xmax); + void fillPolyColor(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisPolygon* poly, const Q_UINT8* col, Q_UINT8* dest, QRect rect); + void cubism(KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect& rect, Q_UINT32 tileSize, Q_UINT32 tileSaturation); + +}; + +#endif diff --git a/krita/plugins/filters/cubismfilter/kis_cubism_filter_plugin.cc b/krita/plugins/filters/cubismfilter/kis_cubism_filter_plugin.cc new file mode 100644 index 00000000..d4cb2a23 --- /dev/null +++ b/krita/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( kritacubismfilter, KisCubismFilterPluginFactory( "krita" ) ) + +KisCubismFilterPlugin::KisCubismFilterPlugin(QObject *parent, const char *name, const QStringList &) : KParts::Plugin(parent, name) +{ + setInstance(KisCubismFilterPluginFactory::instance()); + + if ( parent->inherits("KisFilterRegistry") ) + { + KisFilterRegistry * r = dynamic_cast(parent); + r->add(new KisCubismFilter()); + } +} + +KisCubismFilterPlugin::~KisCubismFilterPlugin() +{ +} + diff --git a/krita/plugins/filters/cubismfilter/kis_cubism_filter_plugin.h b/krita/plugins/filters/cubismfilter/kis_cubism_filter_plugin.h new file mode 100644 index 00000000..09217b1c --- /dev/null +++ b/krita/plugins/filters/cubismfilter/kis_cubism_filter_plugin.h @@ -0,0 +1,32 @@ +/* + * This file is part of Krita + * + * 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(QObject *parent, const char *name, const QStringList &); + virtual ~KisCubismFilterPlugin(); +}; + +#endif diff --git a/krita/plugins/filters/cubismfilter/kis_polygon.cc b/krita/plugins/filters/cubismfilter/kis_polygon.cc new file mode 100644 index 00000000..de5547af --- /dev/null +++ b/krita/plugins/filters/cubismfilter/kis_polygon.cc @@ -0,0 +1,102 @@ +/* + * This file is part of Krita + * + * 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 ); + } +} + +Q_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; +} + +Q_INT32 KisPolygon::numberOfPoints() +{ + return count(); +} + diff --git a/krita/plugins/filters/cubismfilter/kis_polygon.h b/krita/plugins/filters/cubismfilter/kis_polygon.h new file mode 100644 index 00000000..1e5f8aa2 --- /dev/null +++ b/krita/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 QValueVector KisPointVector; +class KisPolygon : public KisPointVector +{ + public: + void addPoint(double x, double y); + void translate(double tx, double ty); + void rotate(double theta); + Q_INT32 extents(double &minX, double &minY, double &maxX, double &maxY); + Q_INT32 numberOfPoints(); +}; + +#endif diff --git a/krita/plugins/filters/cubismfilter/kritacubismfilter.desktop b/krita/plugins/filters/cubismfilter/kritacubismfilter.desktop new file mode 100644 index 00000000..66da8858 --- /dev/null +++ b/krita/plugins/filters/cubismfilter/kritacubismfilter.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=Krita/Filter +Type=Service +X-KDE-Library=kritacubismfilter +X-Krita-Version=2 diff --git a/krita/plugins/filters/embossfilter/Makefile.am b/krita/plugins/filters/embossfilter/Makefile.am new file mode 100644 index 00000000..18a3fed7 --- /dev/null +++ b/krita/plugins/filters/embossfilter/Makefile.am @@ -0,0 +1,23 @@ +kde_services_DATA = kritaembossfilter.desktop + +INCLUDES = \ + -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../ui \ + -I$(srcdir)/../../../../lib/kofficecore \ + -I$(srcdir)/../../../../lib/kofficeui \ + $(all_includes) + +kde_module_LTLIBRARIES = kritaembossfilter.la + +kritaembossfilter_la_SOURCES = kis_emboss_filter_plugin.cc \ + kis_emboss_filter.cc + +noinst_HEADERS = kis_emboss_filter_plugin.h \ + kis_emboss_filter.h + +kritaembossfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritaembossfilter_la_LIBADD = ../../../libkritacommon.la + +kritaembossfilter_la_METASOURCES = AUTO diff --git a/krita/plugins/filters/embossfilter/kis_emboss_filter.cc b/krita/plugins/filters/embossfilter/kis_emboss_filter.cc new file mode 100644 index 00000000..3fea6bb6 --- /dev/null +++ b/krita/plugins/filters/embossfilter/kis_emboss_filter.cc @@ -0,0 +1,179 @@ +/* + * This file is part of Krita + * + * 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 QRect& rect) +{ + Q_UNUSED(dst); + + + //read the filter configuration values from the KisFilterConfiguration object + Q_UINT32 embossdepth = ((KisEmbossFilterConfiguration*)configuration)->depth(); + + //the actual filter function from digikam. It needs a pointer to a Q_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 QRect& 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); + QColor color1; + QColor color2; + Q_UINT8 opacity; + Q_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()->toQColor(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 + (Q_UINT8_MAX / 2))); + G = abs((int)((color1.green() - color2.green()) * Depth + (Q_UINT8_MAX / 2))); + B = abs((int)((color1.blue() - color2.blue()) * Depth + (Q_UINT8_MAX / 2))); + + Gray = CLAMP((R + G + B) / 3, 0, Q_UINT8_MAX); + + dst->colorSpace()->fromQColor(QColor(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(QWidget* parent, KisPaintDeviceSP) +{ + vKisIntegerWidgetParam param; + param.push_back( KisIntegerWidgetParam( 10, 300, 30, i18n("Depth"), "depth" ) ); + KisFilterConfigWidget * w = new KisMultiIntegerFilterWidget(parent, id().id().ascii(), id().id().ascii(), param ); + Q_CHECK_PTR(w); + return w; +} + +KisFilterConfiguration* KisEmbossFilter::configuration(QWidget* nwidget) +{ + KisMultiIntegerFilterWidget* widget = (KisMultiIntegerFilterWidget*) nwidget; + if( widget == 0 ) + { + return new KisEmbossFilterConfiguration( 30 ); + } else { + return new KisEmbossFilterConfiguration( widget->valueAt( 0 ) ); + } +} diff --git a/krita/plugins/filters/embossfilter/kis_emboss_filter.h b/krita/plugins/filters/embossfilter/kis_emboss_filter.h new file mode 100644 index 00000000..9ab9ba7c --- /dev/null +++ b/krita/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(Q_UINT32 depth) + : KisFilterConfiguration( "emboss", 1 ) + { + setProperty("depth", depth); + }; +public: + inline Q_UINT32 depth() { return getInt("depth"); }; +}; + +class KisEmbossFilter : public KisFilter +{ +public: + KisEmbossFilter(); +public: + virtual void process(KisPaintDeviceSP,KisPaintDeviceSP, KisFilterConfiguration* , const QRect&); + 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(QWidget* parent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(QWidget*); + virtual KisFilterConfiguration* configuration() {return new KisEmbossFilterConfiguration( 30 );}; + +private: + void Emboss(KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect& rect, int d); + inline int Lim_Max (int Now, int Up, int Max); +}; + +#endif diff --git a/krita/plugins/filters/embossfilter/kis_emboss_filter_plugin.cc b/krita/plugins/filters/embossfilter/kis_emboss_filter_plugin.cc new file mode 100644 index 00000000..b5b45524 --- /dev/null +++ b/krita/plugins/filters/embossfilter/kis_emboss_filter_plugin.cc @@ -0,0 +1,40 @@ +/* + * This file is part of Krita + * + * 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( kritaembossfilter, KisEmbossFilterPluginFactory( "krita" ) ) + +KisEmbossFilterPlugin::KisEmbossFilterPlugin(QObject *parent, const char *name, const QStringList &) : KParts::Plugin(parent, name) +{ + setInstance(KisEmbossFilterPluginFactory::instance()); + + if (parent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(parent); + manager->add(new KisEmbossFilter()); + } +} + +KisEmbossFilterPlugin::~KisEmbossFilterPlugin() +{ +} diff --git a/krita/plugins/filters/embossfilter/kis_emboss_filter_plugin.h b/krita/plugins/filters/embossfilter/kis_emboss_filter_plugin.h new file mode 100644 index 00000000..6a05d555 --- /dev/null +++ b/krita/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(QObject *parent, const char *name, const QStringList &); + virtual ~KisEmbossFilterPlugin(); +}; + +#endif + diff --git a/krita/plugins/filters/embossfilter/kritaembossfilter.desktop b/krita/plugins/filters/embossfilter/kritaembossfilter.desktop new file mode 100644 index 00000000..6013bad6 --- /dev/null +++ b/krita/plugins/filters/embossfilter/kritaembossfilter.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=Krita/Filter +Type=Service +X-KDE-Library=kritaembossfilter +X-Krita-Version=2 diff --git a/krita/plugins/filters/example/Makefile.am b/krita/plugins/filters/example/Makefile.am new file mode 100644 index 00000000..17be46ce --- /dev/null +++ b/krita/plugins/filters/example/Makefile.am @@ -0,0 +1,21 @@ +kritarcdir = $(kde_datadir)/krita/kritaplugins + +kde_services_DATA = kritaexample.desktop + + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kritaexample_la_SOURCES = example.cc + +kde_module_LTLIBRARIES = kritaexample.la +noinst_HEADERS = example.h + +kritaexample_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritaexample_la_LIBADD = ../../../libkritacommon.la + +kritaexample_la_METASOURCES = AUTO diff --git a/krita/plugins/filters/example/example.cc b/krita/plugins/filters/example/example.cc new file mode 100644 index 00000000..83a03f86 --- /dev/null +++ b/krita/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 KritaExampleFactory; +K_EXPORT_COMPONENT_FACTORY( kritaexample, KritaExampleFactory( "krita" ) ) + +KritaExample::KritaExample(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(KritaExampleFactory::instance()); + + + if (parent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(parent); + manager->add(new KisFilterInvert()); + } +} + +KritaExample::~KritaExample() +{ +} + +KisFilterInvert::KisFilterInvert() : KisFilter(id(), "adjust", i18n("&Invert")) +{ +} + +void KisFilterInvert::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* /*config*/, const QRect& 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(); + Q_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/krita/plugins/filters/example/example.h b/krita/plugins/filters/example/example.h new file mode 100644 index 00000000..4e55da93 --- /dev/null +++ b/krita/plugins/filters/example/example.h @@ -0,0 +1,47 @@ +/* + * This file is part of Krita + * + * 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 KritaExample : public KParts::Plugin +{ +public: + KritaExample(QObject *parent, const char *name, const QStringList &); + virtual ~KritaExample(); +}; + +class KisFilterInvert : public KisFilter +{ +public: + KisFilterInvert(); +public: + virtual void process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration*, const QRect&); + 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/krita/plugins/filters/example/kritaexample.desktop b/krita/plugins/filters/example/kritaexample.desktop new file mode 100644 index 00000000..c28b4274 --- /dev/null +++ b/krita/plugins/filters/example/kritaexample.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=Krita/Filter +Type=Service +X-KDE-Library=kritaexample +X-Krita-Version=2 diff --git a/krita/plugins/filters/fastcolortransfer/Makefile.am b/krita/plugins/filters/fastcolortransfer/Makefile.am new file mode 100644 index 00000000..9c0d141c --- /dev/null +++ b/krita/plugins/filters/fastcolortransfer/Makefile.am @@ -0,0 +1,22 @@ +kritarcdir = $(kde_datadir)/krita/kritaplugins + +kde_services_DATA = kritafastcolortransfer.desktop + + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kritafastcolortransfer_la_SOURCES = wdgfastcolortransfer.ui fastcolortransfer.cc \ + kis_wdg_fastcolortransfer.cpp + +kde_module_LTLIBRARIES = kritafastcolortransfer.la +noinst_HEADERS = fastcolortransfer.h kis_wdg_fastcolortransfer.h + +kritafastcolortransfer_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritafastcolortransfer_la_LIBADD = ../../../libkritacommon.la + +METASOURCES = AUTO diff --git a/krita/plugins/filters/fastcolortransfer/fastcolortransfer.cc b/krita/plugins/filters/fastcolortransfer/fastcolortransfer.cc new file mode 100644 index 00000000..ce9a7a90 --- /dev/null +++ b/krita/plugins/filters/fastcolortransfer/fastcolortransfer.cc @@ -0,0 +1,206 @@ +/* + * This file is part of Krita + * + * 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 KritaFastColorTransferFactory; +K_EXPORT_COMPONENT_FACTORY( kritafastcolortransfer, KritaFastColorTransferFactory( "krita" ) ) + + +FastColorTransferPlugin::FastColorTransferPlugin(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(KritaFastColorTransferFactory::instance()); + + kdDebug(41006) << "Color Transfer Filter plugin. Class: " + << className() + << ", Parent: " + << parent -> className() + << "\n"; + + if (parent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(parent); + manager->add(new KisFilterFastColorTransfer()); + } +} + +FastColorTransferPlugin::~FastColorTransferPlugin() +{ +} + +KisFilterFastColorTransfer::KisFilterFastColorTransfer() : KisFilter(id(), "colors", i18n("&Color Transfer...")) +{ +} + + +KisFilterConfigWidget * KisFilterFastColorTransfer::createConfigurationWidget(QWidget* parent, KisPaintDeviceSP ) +{ + return new KisWdgFastColorTransfer(this, parent, "configuration of color to alpha"); +} + +KisFilterConfiguration* KisFilterFastColorTransfer::configuration(QWidget* 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 QRect& rect) +{ + kdDebug() << "Start transfering color" << endl; + QVariant value; + QString 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 Q_UINT16* data = reinterpret_cast(srcLABIt.oldRawData()); + Q_UINT32 L = data[0]; + Q_UINT32 A = data[1]; + Q_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 Q_UINT16* data = reinterpret_cast(refIt.oldRawData()); + Q_UINT32 L = data[0]; + Q_UINT32 A = data[1]; + Q_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()) + { + Q_UINT16* data = reinterpret_cast(dstIt.rawData()); + data[0] = (Q_UINT16)CLAMP( ( (double)data[0] - meanL_src) * coefL + meanL_ref, 0., 65535.); + data[1] = (Q_UINT16)CLAMP( ( (double)data[1] - meanA_src) * coefA + meanA_ref, 0., 65535.); + data[2] = (Q_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/krita/plugins/filters/fastcolortransfer/fastcolortransfer.h b/krita/plugins/filters/fastcolortransfer/fastcolortransfer.h new file mode 100644 index 00000000..0a156a4f --- /dev/null +++ b/krita/plugins/filters/fastcolortransfer/fastcolortransfer.h @@ -0,0 +1,55 @@ +/* + * This file is part of Krita + * + * 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(QObject *parent, const char *name, const QStringList &); + virtual ~FastColorTransferPlugin(); +}; + +class KisFilterFastColorTransfer : public KisFilter +{ + public: + KisFilterFastColorTransfer(); + public: + virtual void process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration*, const QRect&); + 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(QWidget* parent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(QWidget*); +}; + +#endif diff --git a/krita/plugins/filters/fastcolortransfer/kis_wdg_fastcolortransfer.cpp b/krita/plugins/filters/fastcolortransfer/kis_wdg_fastcolortransfer.cpp new file mode 100644 index 00000000..f6a3e735 --- /dev/null +++ b/krita/plugins/filters/fastcolortransfer/kis_wdg_fastcolortransfer.cpp @@ -0,0 +1,50 @@ +/* + * This file is part of Krita + * + * 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, QWidget * parent, const char * name) : KisFilterConfigWidget ( parent, name ) +{ + QGridLayout *widgetLayout = new QGridLayout(this, 1, 1); + m_widget = new WdgFastColorTransfer(this); + widgetLayout -> addWidget(m_widget,0,0); + connect(m_widget->fileNameURLRequester, SIGNAL(textChanged(const QString&)), this, SIGNAL(sigPleaseUpdatePreview())); +} + + +KisWdgFastColorTransfer::~KisWdgFastColorTransfer() +{ +} + +void KisWdgFastColorTransfer::setConfiguration(KisFilterConfiguration* config) +{ + QVariant value; + if (config->getProperty("filename", value)) + { + widget()->fileNameURLRequester->setURL( value.toString() ); + } + +} diff --git a/krita/plugins/filters/fastcolortransfer/kis_wdg_fastcolortransfer.h b/krita/plugins/filters/fastcolortransfer/kis_wdg_fastcolortransfer.h new file mode 100644 index 00000000..1110551a --- /dev/null +++ b/krita/plugins/filters/fastcolortransfer/kis_wdg_fastcolortransfer.h @@ -0,0 +1,47 @@ +/* + * This file is part of Krita + * + * 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, QWidget * parent, const char * name); + ~KisWdgFastColorTransfer(); + virtual void setConfiguration(KisFilterConfiguration*); + inline WdgFastColorTransfer* widget() { return m_widget; } + private: + WdgFastColorTransfer* m_widget; +}; + +#endif diff --git a/krita/plugins/filters/fastcolortransfer/kritafastcolortransfer.desktop b/krita/plugins/filters/fastcolortransfer/kritafastcolortransfer.desktop new file mode 100644 index 00000000..c345639c --- /dev/null +++ b/krita/plugins/filters/fastcolortransfer/kritafastcolortransfer.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=Krita/Filter +Type=Service +X-KDE-Library=kritafastcolortransfer +X-Krita-Version=2 diff --git a/krita/plugins/filters/fastcolortransfer/wdgfastcolortransfer.ui b/krita/plugins/filters/fastcolortransfer/wdgfastcolortransfer.ui new file mode 100644 index 00000000..fe67e79e --- /dev/null +++ b/krita/plugins/filters/fastcolortransfer/wdgfastcolortransfer.ui @@ -0,0 +1,75 @@ + +WdgFastColorTransfer + + + WdgFastColorTransfer + + + + 0 + 0 + 236 + 112 + + + + + unnamed + + + 0 + + + + layout1 + + + + 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/krita/plugins/filters/halftone/kis_halftone.cpp b/krita/plugins/filters/halftone/kis_halftone.cpp new file mode 100644 index 00000000..f67da1b5 --- /dev/null +++ b/krita/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 KritaHalftoneFactory; +K_EXPORT_COMPONENT_FACTORY( kritahalftone, KritaHalftoneFactory( "krita" ) ) + + KritaHalftone::KritaHalftone(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(KritaHalftoneFactory::instance()); + + kdDebug(41006) << "Halftone filter plugin. Class: " + << className() + << ", Parent: " + << parent->className() + << "\n"; + + + if ( parent->inherits("KisFilterRegistry") ) + { + KisFilterRegistry * r = dynamic_cast(parent); + r->add(new KisHalftoneReduction()); + } +} + +KritaHalftone::~KritaHalftone() +{ +} + + + +KisHalftoneReduction::KisHalftoneReduction() + : KisFilter(id(), "enhance", i18n("Halftone Reduction...")) +{ +} + + +KisHalftoneReduction::~KisHalftoneReduction() +{ +} + +KisFilterConfigWidget * KisHalftoneReduction::createConfigurationWidget(QWidget* parent, 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(parent, id().id().ascii(), id().id().ascii(), param ); +} + +KisFilterConfiguration* KisHalftoneReduction::configuration(QWidget* 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 QRect& 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; + } + + + Q_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, SIGNAL(nextStep()), this, 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); + + QImage mask; + kas->createBrush(&mask); + + KisKernelSP kernel = KisKernel::fromQImage(mask); // TODO: for 1.6 reuse the krita's core function for creating kernel : KisKernel::fromQImage + mask.save("testmask.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, SIGNAL(nextStep()), this, SLOT(incProgress())); + + setProgressDone(); // Must be called even if you don't really support progression +} diff --git a/krita/plugins/filters/halftone/kis_halftone.h b/krita/plugins/filters/halftone/kis_halftone.h new file mode 100644 index 00000000..57c0d874 --- /dev/null +++ b/krita/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 KritaHalftone : public KParts::Plugin +{ + public: + KritaHalftone(QObject *parent, const char *name, const QStringList &); + virtual ~KritaHalftone(); +}; + + +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 QRect&); + virtual KisFilterConfiguration * configuration(QWidget* nwidget); + virtual KisFilterConfiguration * configuration() {return new KisHalftoneReductionConfiguration( BEST_WAVELET_FREQUENCY_VALUE, 2 );}; + virtual KisFilterConfigWidget * createConfigurationWidget(QWidget* parent, 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/krita/plugins/filters/imageenhancement/Makefile.am b/krita/plugins/filters/imageenhancement/Makefile.am new file mode 100644 index 00000000..ff08fa27 --- /dev/null +++ b/krita/plugins/filters/imageenhancement/Makefile.am @@ -0,0 +1,26 @@ +kritarcdir = $(kde_datadir)/krita/kritaplugins + +kde_services_DATA = kritaimageenhancement.desktop + + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kritaimageenhancement_la_SOURCES = imageenhancement.cpp \ + kis_simple_noise_reducer.cpp kis_wavelet_noise_reduction.cpp + +kde_module_LTLIBRARIES = kritaimageenhancement.la + +kritaimageenhancement_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) + +noinst_HEADERS = imageenhancement.h kis_wavelet_noise_reduction.h + +kritaimageenhancement_la_LIBADD = ../../../libkritacommon.la + +kritaimageenhencement_la_METASOURCES = AUTO + +KDE_CXXFLAGS = $(USE_EXCEPTIONS) diff --git a/krita/plugins/filters/imageenhancement/imageenhancement.cpp b/krita/plugins/filters/imageenhancement/imageenhancement.cpp new file mode 100644 index 00000000..12a0f22a --- /dev/null +++ b/krita/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 KritaImageEnhancementFactory; +K_EXPORT_COMPONENT_FACTORY( kritaimageenhancement, KritaImageEnhancementFactory( "krita" ) ) + + KritaImageEnhancement::KritaImageEnhancement(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(KritaImageEnhancementFactory::instance()); + + kdDebug(41006) << "Image enhancement filter plugin. Class: " + << className() + << ", Parent: " + << parent->className() + << "\n"; + + + if ( parent->inherits("KisFilterRegistry") ) + { + KisFilterRegistry * r = dynamic_cast(parent); + r->add(new KisSimpleNoiseReducer()); + r->add(new KisWaveletNoiseReduction()); + } +} + +KritaImageEnhancement::~KritaImageEnhancement() +{ +} + diff --git a/krita/plugins/filters/imageenhancement/imageenhancement.h b/krita/plugins/filters/imageenhancement/imageenhancement.h new file mode 100644 index 00000000..0d06c9b0 --- /dev/null +++ b/krita/plugins/filters/imageenhancement/imageenhancement.h @@ -0,0 +1,34 @@ +/* + * This file is part of Krita + * + * 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 KritaImageEnhancement : public KParts::Plugin +{ + public: + KritaImageEnhancement(QObject *parent, const char *name, const QStringList &); + virtual ~KritaImageEnhancement(); +}; + +#endif diff --git a/krita/plugins/filters/imageenhancement/kis_simple_noise_reducer.cpp b/krita/plugins/filters/imageenhancement/kis_simple_noise_reducer.cpp new file mode 100644 index 00000000..a4fa8f50 --- /dev/null +++ b/krita/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(QWidget* parent, 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(parent, id().id().ascii(), id().id().ascii(), param ); +} + +KisFilterConfiguration* KisSimpleNoiseReducer::configuration(QWidget* 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 QRect& 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 mask + KisAutobrushShape* kas = new KisAutobrushCircleShape(2*windowsize+1, 2*windowsize+1, windowsize, windowsize); + + QImage mask; + kas->createBrush(&mask); + + KisKernelSP kernel = KisKernel::fromQImage(mask); + + 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()) + { + Q_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/krita/plugins/filters/imageenhancement/kis_simple_noise_reducer.h b/krita/plugins/filters/imageenhancement/kis_simple_noise_reducer.h new file mode 100644 index 00000000..40523823 --- /dev/null +++ b/krita/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 QRect&); + virtual KisFilterConfiguration * configuration(QWidget* nwidget); + virtual KisFilterConfiguration * configuration() { return new KisSimpleNoiseReducerConfiguration( 50, 1); }; + virtual KisFilterConfigWidget * createConfigurationWidget(QWidget* parent, 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/krita/plugins/filters/imageenhancement/kis_wavelet_noise_reduction.cpp b/krita/plugins/filters/imageenhancement/kis_wavelet_noise_reduction.cpp new file mode 100644 index 00000000..8792928b --- /dev/null +++ b/krita/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(QWidget* parent, KisPaintDeviceSP ) +{ + vKisDoubleWidgetParam param; + param.push_back( KisDoubleWidgetParam( 0.0, 256.0, BEST_WAVELET_THRESHOLD_VALUE, i18n("Threshold"), "threshold" ) ); + return new KisMultiDoubleFilterWidget(parent, id().id().ascii(), id().id().ascii(), param ); +} + +KisFilterConfiguration* KisWaveletNoiseReduction::configuration(QWidget* 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 QRect& rect) +{ + + float threshold = 1.0; + + if(config !=0) + { + KisWaveletNoiseReductionConfiguration* configWNRC = (KisWaveletNoiseReductionConfiguration*)config; + kdDebug() << "threshold: " << configWNRC->threshold() << endl; + threshold = configWNRC->threshold(); + } + + + Q_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, SIGNAL(nextStep()), this, 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, SIGNAL(nextStep()), this, SLOT(incProgress())); + + setProgressDone(); // Must be called even if you don't really support progression +} diff --git a/krita/plugins/filters/imageenhancement/kis_wavelet_noise_reduction.h b/krita/plugins/filters/imageenhancement/kis_wavelet_noise_reduction.h new file mode 100644 index 00000000..289cb487 --- /dev/null +++ b/krita/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 QRect&); + virtual KisFilterConfiguration * configuration(QWidget* nwidget); + virtual KisFilterConfiguration * configuration() {return new KisWaveletNoiseReductionConfiguration( BEST_WAVELET_THRESHOLD_VALUE );}; + virtual KisFilterConfigWidget * createConfigurationWidget(QWidget* parent, 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/krita/plugins/filters/imageenhancement/kritaimageenhancement.desktop b/krita/plugins/filters/imageenhancement/kritaimageenhancement.desktop new file mode 100644 index 00000000..7184e26d --- /dev/null +++ b/krita/plugins/filters/imageenhancement/kritaimageenhancement.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=Krita/Filter +Type=Service +X-KDE-Library=kritaimageenhancement +X-Krita-Version=2 diff --git a/krita/plugins/filters/lenscorrectionfilter/Makefile.am b/krita/plugins/filters/lenscorrectionfilter/Makefile.am new file mode 100644 index 00000000..77f47e89 --- /dev/null +++ b/krita/plugins/filters/lenscorrectionfilter/Makefile.am @@ -0,0 +1,22 @@ +kritarcdir = $(kde_datadir)/krita/kritaplugins + +kde_services_DATA = kritalenscorrectionfilter.desktop + + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kritalenscorrectionfilter_la_SOURCES = lenscorrectionfilter.cc \ + wdglenscorrectionoptions.ui kis_wdg_lens_correction.cpp + +kde_module_LTLIBRARIES = kritalenscorrectionfilter.la +noinst_HEADERS = lenscorrectionfilter.h + +kritalenscorrectionfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritalenscorrectionfilter_la_LIBADD = ../../../libkritacommon.la + +METASOURCES = AUTO diff --git a/krita/plugins/filters/lenscorrectionfilter/kis_wdg_lens_correction.cpp b/krita/plugins/filters/lenscorrectionfilter/kis_wdg_lens_correction.cpp new file mode 100644 index 00000000..17178379 --- /dev/null +++ b/krita/plugins/filters/lenscorrectionfilter/kis_wdg_lens_correction.cpp @@ -0,0 +1,74 @@ +/* + * This file is part of Krita + * + * 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*/, QWidget* parent, const char* name) + : KisFilterConfigWidget(parent,name) +{ + QGridLayout *widgetLayout = new QGridLayout(this, 1, 1); + m_widget = new WdgLensCorrectionOptions(this); + widgetLayout -> addWidget(m_widget, 0, 0); + + connect( widget()->intXCenter, SIGNAL( valueChanged(int)), SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->intYCenter, SIGNAL( valueChanged(int)), SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->dblCorrectionNearCenter, SIGNAL( valueChanged(double)), SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->dblCorrectionNearEdges, SIGNAL( valueChanged(double)), SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->dblBrightness, SIGNAL( valueChanged(double)), SIGNAL(sigPleaseUpdatePreview())); +} + +KisWdgLensCorrection::~KisWdgLensCorrection() +{ +} + +void KisWdgLensCorrection::setConfiguration(KisFilterConfiguration* config) +{ + QVariant 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/krita/plugins/filters/lenscorrectionfilter/kis_wdg_lens_correction.h b/krita/plugins/filters/lenscorrectionfilter/kis_wdg_lens_correction.h new file mode 100644 index 00000000..9bb8aef5 --- /dev/null +++ b/krita/plugins/filters/lenscorrectionfilter/kis_wdg_lens_correction.h @@ -0,0 +1,43 @@ +/* + * This file is part of Krita + * + * 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 + public: + KisWdgLensCorrection(KisFilter* nfilter, QWidget* parent = 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/krita/plugins/filters/lenscorrectionfilter/kritalenscorrectionfilter.desktop b/krita/plugins/filters/lenscorrectionfilter/kritalenscorrectionfilter.desktop new file mode 100644 index 00000000..712e42b2 --- /dev/null +++ b/krita/plugins/filters/lenscorrectionfilter/kritalenscorrectionfilter.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=Krita/Filter +Type=Service +X-KDE-Library=kritalenscorrectionfilter +X-Krita-Version=2 diff --git a/krita/plugins/filters/lenscorrectionfilter/lenscorrectionfilter.cc b/krita/plugins/filters/lenscorrectionfilter/lenscorrectionfilter.cc new file mode 100644 index 00000000..3dbd25d8 --- /dev/null +++ b/krita/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 KritaLensCorrectionFilterFactory; +K_EXPORT_COMPONENT_FACTORY( kritalenscorrectionfilter, KritaLensCorrectionFilterFactory( "krita" ) ) + +KritaLensCorrectionFilter::KritaLensCorrectionFilter(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(KritaLensCorrectionFilterFactory::instance()); + + + if (parent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(parent); + manager->add(new KisFilterLensCorrection()); + } +} + +KritaLensCorrectionFilter::~KritaLensCorrectionFilter() +{ +} + +KisFilterLensCorrection::KisFilterLensCorrection() : KisFilter(id(), "other", i18n("&Lens Correction...")) +{ +} + +KisFilterConfiguration* KisFilterLensCorrection::configuration(QWidget* w) +{ + QVariant 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(QWidget* parent, KisPaintDeviceSP /*dev*/) +{ + return new KisWdgLensCorrection((KisFilter*)this, (QWidget*)parent, i18n("Configuration of lens correction filter").ascii()); +} + +void KisFilterLensCorrection::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* config, const QRect& rawrect) +{ + Q_ASSERT(src != 0); + Q_ASSERT(dst != 0); + + QRect layerrect = src->exactBounds(); + + QRect workingrect = layerrect.intersect( rawrect ); + + setProgressTotalSteps(workingrect.width() * workingrect.height()); + + KisColorSpace* cs = dst->colorSpace(); + + QVariant 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; + + Q_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(), (Q_UINT8*)lab, 1); + lab[0] = CLAMP( lab[0] * static_cast( brighten ), 0, 65535); + cs->fromLabA16( (Q_UINT8*)lab, dstIt.rawData(), 1); + + ++dstIt; + incProgress(); + } + setProgressDone(); // Must be called even if you don't really support progression +} diff --git a/krita/plugins/filters/lenscorrectionfilter/lenscorrectionfilter.h b/krita/plugins/filters/lenscorrectionfilter/lenscorrectionfilter.h new file mode 100644 index 00000000..a73ac30b --- /dev/null +++ b/krita/plugins/filters/lenscorrectionfilter/lenscorrectionfilter.h @@ -0,0 +1,53 @@ +/* + * This file is part of Krita + * + * 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 KritaLensCorrectionFilter : public KParts::Plugin +{ +public: + KritaLensCorrectionFilter(QObject *parent, const char *name, const QStringList &); + virtual ~KritaLensCorrectionFilter(); +}; + +class KisFilterLensCorrection : public KisFilter +{ + public: + KisFilterLensCorrection(); + public: + virtual void process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration*, const QRect&); + 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(QWidget* parent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(QWidget*); +}; + +#endif diff --git a/krita/plugins/filters/lenscorrectionfilter/wdglenscorrectionoptions.ui b/krita/plugins/filters/lenscorrectionfilter/wdglenscorrectionoptions.ui new file mode 100644 index 00000000..4d60a8bd --- /dev/null +++ b/krita/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/krita/plugins/filters/levelfilter/Makefile.am b/krita/plugins/filters/levelfilter/Makefile.am new file mode 100644 index 00000000..b72bc055 --- /dev/null +++ b/krita/plugins/filters/levelfilter/Makefile.am @@ -0,0 +1,24 @@ +kde_services_DATA = kritalevelfilter.desktop + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kritalevelfilter_la_SOURCES = levelfilter.cc \ + wdg_level.ui \ + kis_level_filter.cc \ + kgradientslider.cc + +noinst_HEADERS = levelfilter.h \ + kis_level_filter.h \ + kgradientslider.h + +kritalevelfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritalevelfilter_la_LIBADD = ../../../libkritacommon.la + +kde_module_LTLIBRARIES = kritalevelfilter.la + +kritalevelfilter_la_METASOURCES = AUTO diff --git a/krita/plugins/filters/levelfilter/kgradientslider.cc b/krita/plugins/filters/levelfilter/kgradientslider.cc new file mode 100644 index 00000000..15fd16fc --- /dev/null +++ b/krita/plugins/filters/levelfilter/kgradientslider.cc @@ -0,0 +1,338 @@ +/* + * This file is part of Krita + * + * 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 + +// Qt includes. + +#include +#include +#include +#include + +// Local includes. + +#include "kgradientslider.h" + +KGradientSlider::KGradientSlider(QWidget *parent, const char *name, WFlags f) + : QWidget(parent, name, f) +{ + m_dragging = false; + + setMouseTracking(true); + setPaletteBackgroundColor(Qt::NoBackground); + setMaximumSize(255, 28); + + m_blackcursor = 0; + m_whitecursor = 255; + m_gamma = 1.0; + m_gammaEnabled = false; + setFocusPolicy(QWidget::StrongFocus); +} + +KGradientSlider::~KGradientSlider() +{ +} + +void KGradientSlider::paintEvent(QPaintEvent *) +{ + int x, y; + int wWidth = width(); + int wHeight = height(); + + int gradientHeight = (wHeight / 3); + + // A QPixmap is used for enable the double buffering. + /*if (!m_dragging) {*/ + QPixmap pm(size()); + QPainter p1; + p1.begin(&pm, this); + + pm.fill(); + + // Draw first gradient + y = 0; + p1.setPen(QPen::QPen(QColor(0,0,0),1, Qt::SolidLine)); + for( x=0; x<255; ++x ) + { + int gray = (255 * x) / wWidth; + p1.setPen(QColor(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, QBrush(Qt::black)); + } + if (m_whitecursor < 255) { + p1.fillRect((int)m_whitecursor, y, 255, gradientHeight, QBrush(Qt::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(QColor(gray, gray, gray)); + p1.drawLine(x, y, x, y + gradientHeight - 1); + } + + // Draw cursors + y = (2 * wHeight / 3); + QPointArray *a = new QPointArray(3); + p1.setPen(Qt::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(Qt::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(Qt::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(Qt::white); + p1.drawPolygon(*a); + + p1.end(); + bitBlt(this, 0, 0, &pm); +} + +void KGradientSlider::mousePressEvent ( QMouseEvent * 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)qRound(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)qRound(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; + } + repaint(false); +} + +void KGradientSlider::mouseReleaseEvent ( QMouseEvent * e ) +{ + if (e->button() != Qt::LeftButton) + return; + + m_dragging = false; + repaint(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 ( QMouseEvent * 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)qRound(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)qRound(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; + } + } + + repaint(false); +} + +void KGradientSlider::leaveEvent( QEvent * ) +{ +} + + +void KGradientSlider::enableGamma(bool b) +{ + m_gammaEnabled = b; + repaint(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)qRound(mid + delta * tmp); + } + repaint(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)qRound(mid + delta * tmp); + } + repaint(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)qRound(mid + delta * tmp); + repaint(false); +} + +#include "kgradientslider.moc" diff --git a/krita/plugins/filters/levelfilter/kgradientslider.h b/krita/plugins/filters/levelfilter/kgradientslider.h new file mode 100644 index 00000000..1640d018 --- /dev/null +++ b/krita/plugins/filters/levelfilter/kgradientslider.h @@ -0,0 +1,84 @@ +/* + * This file is part of Krita + * + * 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 + +// Qt includes. + +#include +#include +#include +#include + +class KGradientSlider : public QWidget +{ +Q_OBJECT + + typedef enum { + BlackCursor, + GammaCursor, + WhiteCursor + } eCursor; + +public: + KGradientSlider(QWidget *parent = 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(QPaintEvent *); + void mousePressEvent (QMouseEvent * e); + void mouseReleaseEvent ( QMouseEvent * e ); + void mouseMoveEvent ( QMouseEvent * e ); + void leaveEvent ( QEvent * ); + +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/krita/plugins/filters/levelfilter/kis_level_filter.cc b/krita/plugins/filters/levelfilter/kis_level_filter.cc new file mode 100644 index 00000000..95f1ad9e --- /dev/null +++ b/krita/plugins/filters/levelfilter/kis_level_filter.cc @@ -0,0 +1,324 @@ +/* + * This file is part of Krita + * + * 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 QString& s ) +{ + KisFilterConfiguration::fromXML(s); + blackvalue = getInt( "blackvalue" ); + whitevalue = getInt( "whitevalue" ); + gammavalue = getDouble( "gammavalue" ); + outblackvalue = getInt( "outblackvalue" ); + outwhitevalue = getInt( "outwhitevalue" ); +} + +QString 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(QWidget *parent, KisPaintDeviceSP dev) +{ + return new KisLevelConfigWidget(parent, dev); +} + +KisFilterConfiguration* KisLevelFilter::configuration(QWidget *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 QRect& 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) { + Q_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()); + Q_INT32 pixelsProcessed = 0; + + while( ! iter.isDone() && !cancelRequested()) + { + Q_UINT32 npix=0, maxpix = iter.nConseqPixels(); + Q_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: + { + Q_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 Q_UINT8 *pixels[2] = {iter.oldRawData(), iter.rawData()}; + Q_UINT8 weights[2] = {MAX_SELECTED - selectedness, selectedness}; + src->colorSpace()->mixColors(pixels, weights, 2, iter.rawData()); + ++iter; + pixelsProcessed++; + break; + } + setProgress(pixelsProcessed); + } + + setProgressDone(); +} + +KisLevelConfigWidget::KisLevelConfigWidget(QWidget * parent, KisPaintDeviceSP dev, const char * name, WFlags f) + : KisFilterConfigWidget(parent, 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); + + QHBoxLayout * l = new QHBoxLayout(this); + Q_CHECK_PTR(l); + l->addWidget(m_page, 0, Qt::AlignTop); + + connect( m_page->blackspin, SIGNAL(valueChanged(int)), SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->whitespin, SIGNAL(valueChanged(int)), SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->ingradient, SIGNAL(modifiedGamma(double)), SIGNAL(sigPleaseUpdatePreview())); + + connect( m_page->blackspin, SIGNAL(valueChanged(int)), m_page->ingradient, SLOT(modifyBlack(int))); + connect( m_page->whitespin, SIGNAL(valueChanged(int)), m_page->ingradient, SLOT(modifyWhite(int))); + //connect( m_page->whitespin, SIGNAL(valueChanged(int)), m_page->ingradient, SLOT(modifyGamma())); + + connect( m_page->ingradient, SIGNAL(modifiedBlack(int)), m_page->blackspin, SLOT(setValue(int))); + connect( m_page->ingradient, SIGNAL(modifiedWhite(int)), m_page->whitespin, SLOT(setValue(int))); + connect( m_page->ingradient, SIGNAL(modifiedGamma(double)), m_page->gammaspin, SLOT(setNum(double))); + + + connect( m_page->outblackspin, SIGNAL(valueChanged(int)), SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->outwhitespin, SIGNAL(valueChanged(int)), SIGNAL(sigPleaseUpdatePreview())); + + connect( m_page->outblackspin, SIGNAL(valueChanged(int)), m_page->outgradient, SLOT(modifyBlack(int))); + connect( m_page->outwhitespin, SIGNAL(valueChanged(int)), m_page->outgradient, SLOT(modifyWhite(int))); + + connect( m_page->outgradient, SIGNAL(modifiedBlack(int)), m_page->outblackspin, SLOT(setValue(int))); + connect( m_page->outgradient, SIGNAL(modifiedWhite(int)), m_page->outwhitespin, SLOT(setValue(int))); + + connect( (QObject*)(m_page->chkLogarithmic), SIGNAL(toggled(bool)), this, 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; + } + + QPixmap pix(256, height); + pix.fill(); + QPainter p(&pix); + p.setPen(QPen::QPen(Qt::gray,1, Qt::SolidLine)); + + double highest = (double)histogram->calculations().getHighest(); + Q_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/krita/plugins/filters/levelfilter/kis_level_filter.h b/krita/plugins/filters/levelfilter/kis_level_filter.h new file mode 100644 index 00000000..5759fe75 --- /dev/null +++ b/krita/plugins/filters/levelfilter/kis_level_filter.h @@ -0,0 +1,93 @@ +/* + * This file is part of Krita + * + * 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 QWidget; +class KisColorAdjustment; +class KisHistogram; + +class KisLevelFilterConfiguration : public KisFilterConfiguration { + +public: + + KisLevelFilterConfiguration(); + virtual ~KisLevelFilterConfiguration(); + virtual void fromXML( const QString& ); + virtual QString toString(); + +public: + Q_UINT8 blackvalue, whitevalue; + double gammavalue; + Q_UINT16 outblackvalue, outwhitevalue; + KisColorAdjustment * m_adjustment; +}; + +/** + * This class affect Intensity Y of the image + */ +class KisLevelFilter : public KisFilter +{ + +public: + + KisLevelFilter(); + +public: + + virtual KisFilterConfigWidget * createConfigurationWidget(QWidget* parent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration * configuration(QWidget *); + virtual KisFilterConfiguration * configuration() { return new KisLevelFilterConfiguration(); }; + virtual void process(KisPaintDeviceSP, KisPaintDeviceSP, KisFilterConfiguration* , const QRect&); + 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 +public: + KisLevelConfigWidget(QWidget * parent, 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/krita/plugins/filters/levelfilter/kritalevelfilter.desktop b/krita/plugins/filters/levelfilter/kritalevelfilter.desktop new file mode 100644 index 00000000..6492dbf1 --- /dev/null +++ b/krita/plugins/filters/levelfilter/kritalevelfilter.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=Krita/Filter +Type=Service +X-KDE-Library=kritalevelfilter +X-Krita-Version=2 diff --git a/krita/plugins/filters/levelfilter/levelfilter.cc b/krita/plugins/filters/levelfilter/levelfilter.cc new file mode 100644 index 00000000..ac7fd4e6 --- /dev/null +++ b/krita/plugins/filters/levelfilter/levelfilter.cc @@ -0,0 +1,67 @@ +/* + * This file is part of Krita + * + * 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( kritalevelfilter, LevelFilterFactory( "krita" ) ) + +LevelFilter::LevelFilter(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(LevelFilterFactory::instance()); + + if (parent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(parent); + manager->add(new KisLevelFilter()); + } +} + +LevelFilter::~LevelFilter() +{ +} diff --git a/krita/plugins/filters/levelfilter/levelfilter.h b/krita/plugins/filters/levelfilter/levelfilter.h new file mode 100644 index 00000000..e382e8a9 --- /dev/null +++ b/krita/plugins/filters/levelfilter/levelfilter.h @@ -0,0 +1,35 @@ +/* + * This file is part of Krita + * + * 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(QObject *parent, const char *name, const QStringList &); + virtual ~LevelFilter(); +}; + +#endif diff --git a/krita/plugins/filters/levelfilter/wdg_level.ui b/krita/plugins/filters/levelfilter/wdg_level.ui new file mode 100644 index 00000000..8a568aeb --- /dev/null +++ b/krita/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> + + + + + layout7 + + + + unnamed + + + + histview + + + + 256 + 256 + + + + + 256 + 256 + + + + true + + + + + layout5 + + + + unnamed + + + + ingradient + + + + 256 + 20 + + + + + + layout5 + + + + 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> + + + + + layout6 + + + + unnamed + + + + outgradient + + + + 256 + 20 + + + + + + layout2 + + + + 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/krita/plugins/filters/noisefilter/Makefile.am b/krita/plugins/filters/noisefilter/Makefile.am new file mode 100644 index 00000000..761cc763 --- /dev/null +++ b/krita/plugins/filters/noisefilter/Makefile.am @@ -0,0 +1,22 @@ +kritarcdir = $(kde_datadir)/krita/kritaplugins + +kde_services_DATA = kritanoisefilter.desktop + + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kritanoisefilter_la_SOURCES = noisefilter.cc wdgnoiseoptions.ui \ + kis_wdg_noise.cpp + +kde_module_LTLIBRARIES = kritanoisefilter.la +noinst_HEADERS = noisefilter.h kis_wdg_noise.h + +kritanoisefilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritanoisefilter_la_LIBADD = ../../../libkritacommon.la + +kritanoisefilter_la_METASOURCES = AUTO diff --git a/krita/plugins/filters/noisefilter/kis_wdg_noise.cpp b/krita/plugins/filters/noisefilter/kis_wdg_noise.cpp new file mode 100644 index 00000000..ae2da57f --- /dev/null +++ b/krita/plugins/filters/noisefilter/kis_wdg_noise.cpp @@ -0,0 +1,59 @@ +/* + * This file is part of Krita + * + * 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*/, QWidget* parent, const char* name) + : KisFilterConfigWidget(parent,name) +{ + QGridLayout *widgetLayout = new QGridLayout(this, 1, 1); + m_widget = new WdgNoiseOptions(this); + widgetLayout -> addWidget(m_widget,0,0); + + connect( widget()->intLevel, SIGNAL( valueChanged(int)), SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->intOpacity, SIGNAL( valueChanged(int)), SIGNAL(sigPleaseUpdatePreview())); +} + +KisWdgNoise::~KisWdgNoise() +{ +} + +void KisWdgNoise::setConfiguration(KisFilterConfiguration* config) +{ + QVariant 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/krita/plugins/filters/noisefilter/kis_wdg_noise.h b/krita/plugins/filters/noisefilter/kis_wdg_noise.h new file mode 100644 index 00000000..297e78a7 --- /dev/null +++ b/krita/plugins/filters/noisefilter/kis_wdg_noise.h @@ -0,0 +1,43 @@ +/* + * This file is part of Krita + * + * 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 + public: + KisWdgNoise(KisFilter* nfilter, QWidget* parent = 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/krita/plugins/filters/noisefilter/kritanoisefilter.desktop b/krita/plugins/filters/noisefilter/kritanoisefilter.desktop new file mode 100644 index 00000000..908a2e61 --- /dev/null +++ b/krita/plugins/filters/noisefilter/kritanoisefilter.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=Krita/Filter +Type=Service +X-KDE-Library=kritanoisefilter +X-Krita-Version=2 diff --git a/krita/plugins/filters/noisefilter/noisefilter.cc b/krita/plugins/filters/noisefilter/noisefilter.cc new file mode 100644 index 00000000..03e73f81 --- /dev/null +++ b/krita/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 KritaNoiseFilterFactory; +K_EXPORT_COMPONENT_FACTORY( kritanoisefilter, KritaNoiseFilterFactory( "krita" ) ) + +KritaNoiseFilter::KritaNoiseFilter(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(KritaNoiseFilterFactory::instance()); + + + if (parent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(parent); + manager->add(new KisFilterNoise()); + } +} + +KritaNoiseFilter::~KritaNoiseFilter() +{ +} + +KisFilterNoise::KisFilterNoise() : KisFilter(id(), "other", i18n("&Random Noise...")) +{ +} + +KisFilterConfiguration* KisFilterNoise::configuration(QWidget* 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(QWidget* parent, KisPaintDeviceSP dev) +{ + return new KisWdgNoise((KisFilter*)this, (QWidget*)parent, i18n("Configuration of noise filter").ascii()); +} + +void KisFilterNoise::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* config, const QRect& rect) +{ + Q_ASSERT(src != 0); + Q_ASSERT(dst != 0); + + setProgressTotalSteps(rect.width() * rect.height()); + + KisColorSpace * cs = src->colorSpace(); + Q_INT32 psize = cs->pixelSize(); + + QVariant 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); + + Q_UINT8* interm = new Q_UINT8[ cs->pixelSize() ]; + Q_UINT32 threshold = (RAND_MAX / 100) * (100 - level); + + Q_UINT8 weights[2]; + weights[0] = (255 * opacity) / 100; weights[1] = 255 - weights[0]; + const Q_UINT8* pixels[2]; + pixels[0] = interm; + while(!srcIt.isDone()) + { + if(rand() > threshold) + { + QColor c = qRgb((double)rand()/RAND_MAX * 255,(double)rand()/RAND_MAX * 255,(double)rand()/RAND_MAX * 255); + cs->fromQColor( 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/krita/plugins/filters/noisefilter/noisefilter.h b/krita/plugins/filters/noisefilter/noisefilter.h new file mode 100644 index 00000000..176129c7 --- /dev/null +++ b/krita/plugins/filters/noisefilter/noisefilter.h @@ -0,0 +1,52 @@ +/* + * This file is part of Krita + * + * 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 KritaNoiseFilter : public KParts::Plugin +{ +public: + KritaNoiseFilter(QObject *parent, const char *name, const QStringList &); + virtual ~KritaNoiseFilter(); +}; + +class KisFilterNoise : public KisFilter +{ + public: + KisFilterNoise(); + public: + virtual void process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration*, const QRect&); + 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(QWidget* parent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(QWidget*); +}; + +#endif diff --git a/krita/plugins/filters/noisefilter/wdgnoiseoptions.ui b/krita/plugins/filters/noisefilter/wdgnoiseoptions.ui new file mode 100644 index 00000000..3a7862ad --- /dev/null +++ b/krita/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/krita/plugins/filters/oilpaintfilter/Makefile.am b/krita/plugins/filters/oilpaintfilter/Makefile.am new file mode 100644 index 00000000..4f114841 --- /dev/null +++ b/krita/plugins/filters/oilpaintfilter/Makefile.am @@ -0,0 +1,23 @@ +kde_services_DATA = kritaoilpaintfilter.desktop + +INCLUDES = \ + -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../ui \ + -I../../../ui/ \ + -I$(srcdir)/../../../../lib/kofficecore \ + $(all_includes) + +kde_module_LTLIBRARIES = kritaoilpaintfilter.la + +kritaoilpaintfilter_la_SOURCES = kis_oilpaint_filter_plugin.cc \ + kis_oilpaint_filter.cc + +noinst_HEADERS = kis_oilpaint_filter_plugin.h \ + kis_oilpaint_filter.h + +kritaoilpaintfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritaoilpaintfilter_la_LIBADD = ../../../libkritacommon.la + +kritaoilpaintfilter_la_METASOURCES = AUTO diff --git a/krita/plugins/filters/oilpaintfilter/kis_oilpaint_filter.cc b/krita/plugins/filters/oilpaintfilter/kis_oilpaint_filter.cc new file mode 100644 index 00000000..bafa2644 --- /dev/null +++ b/krita/plugins/filters/oilpaintfilter/kis_oilpaint_filter.cc @@ -0,0 +1,256 @@ +/* + * This file is part of Krita + * + * 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 QRect& rect) +{ + + if (!configuration) { + kdWarning() << "No configuration object for oilpaint filter\n"; + return; + } + + Q_UNUSED(dst); + + Q_INT32 x = rect.x(), y = rect.y(); + Q_INT32 width = rect.width(); + Q_INT32 height = rect.height(); + + //read the filter configuration values from the KisFilterConfiguration object + Q_UINT32 brushSize = ((KisOilPaintFilterConfiguration*)configuration)->brushSize(); + Q_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); + + QRect bounds(x, y, w, h); + + for (Q_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()->fromQColor(QColor(qRed(color), qGreen(color), qBlue(color)), qAlpha(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 QRect& 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.contains(it.x(), it.y())) { + +// XXX: COLORSPACE_INDEPENDENCE + + QColor c; + src->colorSpace()->toQColor(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 = qRgb (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(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 KisOilPaintFilter::listOfExamplesConfiguration(KisPaintDeviceSP ) +{ + std::list list; + list.insert(list.begin(), new KisOilPaintFilterConfiguration( 1, 30)); + return list; +} + diff --git a/krita/plugins/filters/oilpaintfilter/kis_oilpaint_filter.h b/krita/plugins/filters/oilpaintfilter/kis_oilpaint_filter.h new file mode 100644 index 00000000..5397cb65 --- /dev/null +++ b/krita/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(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"); }; + +}; + + +class KisOilPaintFilter : public KisFilter +{ +public: + KisOilPaintFilter(); +public: + virtual void process(KisPaintDeviceSP,KisPaintDeviceSP, KisFilterConfiguration* , const QRect&); + 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(QWidget* parent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration * configuration(QWidget*); + 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 QRect& 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/krita/plugins/filters/oilpaintfilter/kis_oilpaint_filter_plugin.cc b/krita/plugins/filters/oilpaintfilter/kis_oilpaint_filter_plugin.cc new file mode 100644 index 00000000..95defb56 --- /dev/null +++ b/krita/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( kritaoilpaintfilter, KisOilPaintFilterPluginFactory( "krita" ) ) + +KisOilPaintFilterPlugin::KisOilPaintFilterPlugin(QObject *parent, const char *name, const QStringList &) : KParts::Plugin(parent, name) +{ + setInstance(KisOilPaintFilterPluginFactory::instance()); + + if (parent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(parent); + manager->add(new KisOilPaintFilter()); + } + +} + +KisOilPaintFilterPlugin::~KisOilPaintFilterPlugin() +{ +} + diff --git a/krita/plugins/filters/oilpaintfilter/kis_oilpaint_filter_plugin.h b/krita/plugins/filters/oilpaintfilter/kis_oilpaint_filter_plugin.h new file mode 100644 index 00000000..e4066a77 --- /dev/null +++ b/krita/plugins/filters/oilpaintfilter/kis_oilpaint_filter_plugin.h @@ -0,0 +1,32 @@ +/* + * This file is part of Krita + * + * 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(QObject *parent, const char *name, const QStringList &); + virtual ~KisOilPaintFilterPlugin(); +}; + +#endif diff --git a/krita/plugins/filters/oilpaintfilter/kritaoilpaintfilter.desktop b/krita/plugins/filters/oilpaintfilter/kritaoilpaintfilter.desktop new file mode 100644 index 00000000..8667c735 --- /dev/null +++ b/krita/plugins/filters/oilpaintfilter/kritaoilpaintfilter.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=Krita/Filter +Type=Service +X-KDE-Library=kritaoilpaintfilter +X-Krita-Version=2 diff --git a/krita/plugins/filters/pixelizefilter/Makefile.am b/krita/plugins/filters/pixelizefilter/Makefile.am new file mode 100644 index 00000000..61d3ddd8 --- /dev/null +++ b/krita/plugins/filters/pixelizefilter/Makefile.am @@ -0,0 +1,23 @@ +kde_services_DATA = kritapixelizefilter.desktop + +INCLUDES = \ + -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../ui \ + -I$(srcdir)/../../../../lib/kofficecore \ + -I$(srcdir)/../../../../lib/kofficeui \ + $(all_includes) + +kde_module_LTLIBRARIES = kritapixelizefilter.la + +kritapixelizefilter_la_SOURCES = kis_pixelize_filter_plugin.cc \ + kis_pixelize_filter.cc + +noinst_HEADERS = kis_pixelize_filter_plugin.h \ + kis_pixelize_filter.h + +kritapixelizefilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritapixelizefilter_la_LIBADD = ../../../libkritacommon.la + +kritapixelizefilter_la_METASOURCES = AUTO diff --git a/krita/plugins/filters/pixelizefilter/kis_pixelize_filter.cc b/krita/plugins/filters/pixelizefilter/kis_pixelize_filter.cc new file mode 100644 index 00000000..dadf9590 --- /dev/null +++ b/krita/plugins/filters/pixelizefilter/kis_pixelize_filter.cc @@ -0,0 +1,188 @@ +/* + * This file is part of Krita + * + * 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 QRect& rect) +{ + Q_ASSERT( src ); + Q_ASSERT( dst ); + Q_ASSERT( configuration ); + Q_ASSERT( rect.isValid() ); + + Q_INT32 x = rect.x(), y = rect.y(); + Q_INT32 width = rect.width(); + Q_INT32 height = rect.height(); + + //read the filter configuration values from the KisFilterConfiguration object + Q_UINT32 pixelWidth = ((KisPixelizeFilterConfiguration*)configuration)->pixelWidth(); + Q_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; + + Q_INT32 pixelSize = src->pixelSize(); + QMemArray average( pixelSize ); + + Q_INT32 count; + + //calculate the total number of pixels + Q_INT32 numX=0; + Q_INT32 numY=0; + + for (Q_INT32 x = startx; x < startx + width; x += pixelWidth - (x % pixelWidth)) + { + numX++; + } + for (Q_INT32 y = starty; y < starty + height; y += pixelHeight - (y % pixelHeight)) + { + numY++; + } + + setProgressTotalSteps( numX * numY ); + setProgressStage(i18n("Applying pixelize filter..."),0); + + Q_INT32 numberOfPixelsProcessed = 0; + + for (Q_INT32 y = starty; y < starty + height; y += pixelHeight - (y % pixelHeight)) + { + Q_INT32 h = pixelHeight - (y % pixelHeight); + h = MIN(h, starty + height - y); + + for (Q_INT32 x = startx; x < startx + width; x += pixelWidth - (x % pixelWidth)) + { + Q_INT32 w = pixelWidth - (x % pixelWidth); + w = MIN(w, startx + width - x); + + for (Q_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 (Q_INT32 i = 0; i < pixelSize; i++) + { + average[i] += srcIt.oldRawData()[i]; + } + count++; + } + ++srcIt; + } + + //average + if (count > 0) + { + for (Q_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(QWidget* parent, 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(parent, id().id().ascii(), id().id().ascii(), param ); +} + +KisFilterConfiguration* KisPixelizeFilter::configuration(QWidget* 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/krita/plugins/filters/pixelizefilter/kis_pixelize_filter.h b/krita/plugins/filters/pixelizefilter/kis_pixelize_filter.h new file mode 100644 index 00000000..16ce62e7 --- /dev/null +++ b/krita/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(Q_UINT32 pixelWidth, Q_UINT32 pixelHeight) + : KisFilterConfiguration( "pixelize", 1 ) + { + setProperty("pixelWidth", pixelWidth); + setProperty("pixelHeight", pixelHeight); + }; +public: + inline Q_UINT32 pixelWidth() { return getInt("pixelWidth"); }; + inline Q_UINT32 pixelHeight() {return getInt("pixelHeight"); }; +}; + +class KisPixelizeFilter : public KisFilter +{ +public: + KisPixelizeFilter(); +public: + virtual void process(KisPaintDeviceSP,KisPaintDeviceSP, KisFilterConfiguration* , const QRect&); + 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(QWidget* parent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(QWidget*); + 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/krita/plugins/filters/pixelizefilter/kis_pixelize_filter_plugin.cc b/krita/plugins/filters/pixelizefilter/kis_pixelize_filter_plugin.cc new file mode 100644 index 00000000..39a56ec5 --- /dev/null +++ b/krita/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( kritapixelizefilter, KisPixelizeFilterPluginFactory( "krita" ) ) + +KisPixelizeFilterPlugin::KisPixelizeFilterPlugin(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(KisPixelizeFilterPluginFactory::instance()); + + if (parent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(parent); + manager->add(new KisPixelizeFilter()); + } +} + +KisPixelizeFilterPlugin::~KisPixelizeFilterPlugin() +{ +} + diff --git a/krita/plugins/filters/pixelizefilter/kis_pixelize_filter_plugin.h b/krita/plugins/filters/pixelizefilter/kis_pixelize_filter_plugin.h new file mode 100644 index 00000000..33edf4d0 --- /dev/null +++ b/krita/plugins/filters/pixelizefilter/kis_pixelize_filter_plugin.h @@ -0,0 +1,32 @@ +/* + * This file is part of Krita + * + * 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(QObject *parent, const char *name, const QStringList &); + virtual ~KisPixelizeFilterPlugin(); +}; + +#endif diff --git a/krita/plugins/filters/pixelizefilter/kritapixelizefilter.desktop b/krita/plugins/filters/pixelizefilter/kritapixelizefilter.desktop new file mode 100644 index 00000000..a1e6a96f --- /dev/null +++ b/krita/plugins/filters/pixelizefilter/kritapixelizefilter.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=Krita/Filter +Type=Service +X-KDE-Library=kritapixelizefilter +X-Krita-Version=2 diff --git a/krita/plugins/filters/raindropsfilter/Makefile.am b/krita/plugins/filters/raindropsfilter/Makefile.am new file mode 100644 index 00000000..6cd42c40 --- /dev/null +++ b/krita/plugins/filters/raindropsfilter/Makefile.am @@ -0,0 +1,23 @@ +kde_services_DATA = kritaraindropsfilter.desktop + +INCLUDES = \ + -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../kritacolor/color_strategy \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = kritaraindropsfilter.la + +kritaraindropsfilter_la_SOURCES = kis_raindrops_filter_plugin.cc \ + kis_raindrops_filter.cc + +noinst_HEADERS = kis_raindrops_filter_plugin.h \ + kis_raindrops_filter.h + +kritaraindropsfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritaraindropsfilter_la_LIBADD = ../../../libkritacommon.la + +kritaraindropsfilter_la_METASOURCES = AUTO diff --git a/krita/plugins/filters/raindropsfilter/kis_raindrops_filter.cc b/krita/plugins/filters/raindropsfilter/kis_raindrops_filter.cc new file mode 100644 index 00000000..a2bd633e --- /dev/null +++ b/krita/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 QRect& rect) +{ + + Q_UNUSED(dst); + + //read the filter configuration values from the KisFilterConfiguration object + Q_UINT32 dropSize = ((KisRainDropsFilterConfiguration*)configuration)->dropSize(); + Q_UINT32 number = ((KisRainDropsFilterConfiguration*)configuration)->number(); + Q_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 QRect& 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(); + + QDateTime dt = QDateTime::currentDateTime(); + QDateTime Y2000( QDate(2000, 1, 1), QTime(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; + + QColor originalColor; + oldIt.moveTo(rect.x() + l, rect.y() + k); + cs->toQColor(oldIt.oldRawData(), &originalColor); + + int newRed = CLAMP(originalColor.red() + Bright, 0, Q_UINT8_MAX); + int newGreen = CLAMP(originalColor.green() + Bright, 0, Q_UINT8_MAX); + int newBlue = CLAMP(originalColor.blue() + Bright, 0, Q_UINT8_MAX); + + QColor newColor; + newColor.setRgb(newRed, newGreen, newBlue); + + dstIt.moveTo(rect.x() + n, rect.y() + m); + cs->fromQColor(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)) + { + QColor color; + dstIt.moveTo(rect.x() + n, rect.y() + m); + + cs->toQColor(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)) + { + QColor color; + + color.setRgb((int)(R / BlurPixels), (int)(G / BlurPixels), (int)(B / BlurPixels)); + dstIt.moveTo(rect.x() + n, rect.y() + m); + + cs->fromQColor(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(QWidget* parent, 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(parent, id().id().ascii(), id().id().ascii(), param ); +} + +KisFilterConfiguration* KisRainDropsFilter::configuration(QWidget* 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/krita/plugins/filters/raindropsfilter/kis_raindrops_filter.h b/krita/plugins/filters/raindropsfilter/kis_raindrops_filter.h new file mode 100644 index 00000000..c4a4d4da --- /dev/null +++ b/krita/plugins/filters/raindropsfilter/kis_raindrops_filter.h @@ -0,0 +1,67 @@ +/* + * This file is part of Krita + * + * 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(Q_UINT32 dropSize, Q_UINT32 number, Q_UINT32 fishEyes) + : KisFilterConfiguration( "raindrops", 1 ) + { + setProperty("dropsize", dropSize); + setProperty("number", number); + setProperty("fishEyes", fishEyes); + }; +public: + inline Q_UINT32 dropSize() { return getInt("dropsize"); }; + inline Q_UINT32 number() {return getInt("number"); }; + inline Q_UINT32 fishEyes() {return getInt("fishEyes"); }; + +}; + +class KisRainDropsFilter : public KisFilter +{ +public: + KisRainDropsFilter(); +public: + virtual void process(KisPaintDeviceSP,KisPaintDeviceSP, KisFilterConfiguration* , const QRect&); + 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(QWidget* parent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(QWidget*); +private: + void rainDrops(KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect& 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/krita/plugins/filters/raindropsfilter/kis_raindrops_filter_plugin.cc b/krita/plugins/filters/raindropsfilter/kis_raindrops_filter_plugin.cc new file mode 100644 index 00000000..9b06b0c0 --- /dev/null +++ b/krita/plugins/filters/raindropsfilter/kis_raindrops_filter_plugin.cc @@ -0,0 +1,44 @@ +/* + * This file is part of Krita + * + * 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( kritaraindropsfilter, KisRainDropsFilterPluginFactory( "krita" ) ) + +KisRainDropsFilterPlugin::KisRainDropsFilterPlugin(QObject *parent, const char *name, const QStringList &) : KParts::Plugin(parent, name) +{ + setInstance(KisRainDropsFilterPluginFactory::instance()); + + if (parent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(parent); + manager->add(new KisRainDropsFilter()); + } +} + +KisRainDropsFilterPlugin::~KisRainDropsFilterPlugin() +{ +} diff --git a/krita/plugins/filters/raindropsfilter/kis_raindrops_filter_plugin.h b/krita/plugins/filters/raindropsfilter/kis_raindrops_filter_plugin.h new file mode 100644 index 00000000..455f8f69 --- /dev/null +++ b/krita/plugins/filters/raindropsfilter/kis_raindrops_filter_plugin.h @@ -0,0 +1,33 @@ +/* + * This file is part of Krita + * + * 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(QObject *parent, const char *name, const QStringList &); + virtual ~KisRainDropsFilterPlugin(); +}; + +#endif diff --git a/krita/plugins/filters/raindropsfilter/kritaraindropsfilter.desktop b/krita/plugins/filters/raindropsfilter/kritaraindropsfilter.desktop new file mode 100644 index 00000000..a8e429f0 --- /dev/null +++ b/krita/plugins/filters/raindropsfilter/kritaraindropsfilter.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=Krita/Filter +Type=Service +X-KDE-Library=kritaraindropsfilter +X-Krita-Version=2 diff --git a/krita/plugins/filters/randompickfilter/Makefile.am b/krita/plugins/filters/randompickfilter/Makefile.am new file mode 100644 index 00000000..9fb1bb90 --- /dev/null +++ b/krita/plugins/filters/randompickfilter/Makefile.am @@ -0,0 +1,22 @@ +kritarcdir = $(kde_datadir)/krita/kritaplugins + +kde_services_DATA = kritarandompickfilter.desktop + + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kritarandompickfilter_la_SOURCES = randompickfilter.cc wdgrandompickoptions.ui \ + kis_wdg_random_pick.cpp + +kde_module_LTLIBRARIES = kritarandompickfilter.la +noinst_HEADERS = randompickfilter.h + +kritarandompickfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritarandompickfilter_la_LIBADD = ../../../libkritacommon.la + +kritarandompickfilter_la_METASOURCES = AUTO diff --git a/krita/plugins/filters/randompickfilter/kis_wdg_random_pick.cpp b/krita/plugins/filters/randompickfilter/kis_wdg_random_pick.cpp new file mode 100644 index 00000000..380b405a --- /dev/null +++ b/krita/plugins/filters/randompickfilter/kis_wdg_random_pick.cpp @@ -0,0 +1,64 @@ +/* + * This file is part of Krita + * + * 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*/, QWidget* parent, const char* name) + : KisFilterConfigWidget(parent,name) +{ + QGridLayout *widgetLayout = new QGridLayout(this, 1, 1); + m_widget = new WdgRandomPickOptions(this); + widgetLayout -> addWidget(m_widget,0,0); + + connect( widget()->intLevel, SIGNAL( valueChanged(int)), SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->intWindowSize, SIGNAL( valueChanged(int)), SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->intOpacity, SIGNAL( valueChanged(int)), SIGNAL(sigPleaseUpdatePreview())); +} + +KisWdgRandomPick::~KisWdgRandomPick() +{ +} + +void KisWdgRandomPick::setConfiguration(KisFilterConfiguration* config) +{ + QVariant 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/krita/plugins/filters/randompickfilter/kis_wdg_random_pick.h b/krita/plugins/filters/randompickfilter/kis_wdg_random_pick.h new file mode 100644 index 00000000..f7d86079 --- /dev/null +++ b/krita/plugins/filters/randompickfilter/kis_wdg_random_pick.h @@ -0,0 +1,43 @@ +/* + * This file is part of Krita + * + * 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 + public: + KisWdgRandomPick(KisFilter* nfilter, QWidget* parent = 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/krita/plugins/filters/randompickfilter/kritarandompickfilter.desktop b/krita/plugins/filters/randompickfilter/kritarandompickfilter.desktop new file mode 100644 index 00000000..d842cc24 --- /dev/null +++ b/krita/plugins/filters/randompickfilter/kritarandompickfilter.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=Krita/Filter +Type=Service +X-KDE-Library=kritarandompickfilter +X-Krita-Version=2 diff --git a/krita/plugins/filters/randompickfilter/randompickfilter.cc b/krita/plugins/filters/randompickfilter/randompickfilter.cc new file mode 100644 index 00000000..3289f683 --- /dev/null +++ b/krita/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 KritaRandomPickFilterFactory; +K_EXPORT_COMPONENT_FACTORY( kritarandompickfilter, KritaRandomPickFilterFactory( "krita" ) ) + +KritaRandomPickFilter::KritaRandomPickFilter(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(KritaRandomPickFilterFactory::instance()); + + + if (parent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(parent); + manager->add(new KisFilterRandomPick()); + } +} + +KritaRandomPickFilter::~KritaRandomPickFilter() +{ +} + +KisFilterRandomPick::KisFilterRandomPick() : KisFilter(id(), "other", i18n("&Random Pick...")) +{ +} + +KisFilterConfiguration* KisFilterRandomPick::configuration(QWidget* 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(QWidget* parent, KisPaintDeviceSP dev) +{ + return new KisWdgRandomPick((KisFilter*)this, (QWidget*)parent, i18n("Configuration of random pick filter").ascii()); +} + +void KisFilterRandomPick::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* config, const QRect& rect) +{ + Q_ASSERT(src != 0); + Q_ASSERT(dst != 0); + + setProgressTotalSteps(rect.height() * rect.width()); + + KisColorSpace * cs = src->colorSpace(); + Q_INT32 psize = cs->pixelSize(); + + QVariant 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); + + Q_UINT32 threshold = (RAND_MAX / 100) * (100 - level); + + Q_UINT8 weights[2]; + weights[0] = (255 * opacity) / 100; weights[1] = 255 - weights[0]; + const Q_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/krita/plugins/filters/randompickfilter/randompickfilter.h b/krita/plugins/filters/randompickfilter/randompickfilter.h new file mode 100644 index 00000000..1d7f2c8f --- /dev/null +++ b/krita/plugins/filters/randompickfilter/randompickfilter.h @@ -0,0 +1,52 @@ +/* + * This file is part of Krita + * + * 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 KritaRandomPickFilter : public KParts::Plugin +{ +public: + KritaRandomPickFilter(QObject *parent, const char *name, const QStringList &); + virtual ~KritaRandomPickFilter(); +}; + +class KisFilterRandomPick : public KisFilter +{ + public: + KisFilterRandomPick(); + public: + virtual void process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration*, const QRect&); + 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(QWidget* parent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(QWidget*); +}; + +#endif diff --git a/krita/plugins/filters/randompickfilter/wdgrandompickoptions.ui b/krita/plugins/filters/randompickfilter/wdgrandompickoptions.ui new file mode 100644 index 00000000..c4cb8947 --- /dev/null +++ b/krita/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/krita/plugins/filters/roundcorners/Makefile.am b/krita/plugins/filters/roundcorners/Makefile.am new file mode 100644 index 00000000..43e6163d --- /dev/null +++ b/krita/plugins/filters/roundcorners/Makefile.am @@ -0,0 +1,22 @@ +kde_services_DATA = kritaroundcornersfilter.desktop + +INCLUDES = \ + -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = kritaroundcornersfilter.la + +kritaroundcornersfilter_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 + +kritaroundcornersfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritaroundcornersfilter_la_LIBADD = ../../../libkritacommon.la + +kritaroundcornersfilter_la_METASOURCES = AUTO diff --git a/krita/plugins/filters/roundcorners/kis_round_corners_filter.cc b/krita/plugins/filters/roundcorners/kis_round_corners_filter.cc new file mode 100644 index 00000000..715a2d58 --- /dev/null +++ b/krita/plugins/filters/roundcorners/kis_round_corners_filter.cc @@ -0,0 +1,158 @@ +/* + * This file is part of Krita + * + * 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 QRect& rect) +{ + //read the filter configuration values from the KisFilterConfiguration object + Q_INT32 radius = (Q_INT32)((KisRoundCornersFilterConfiguration*)configuration)->radius(); + Q_UINT32 pixelSize = src->pixelSize(); + + setProgressTotalSteps( rect.height() ); + setProgressStage(i18n("Applying pixelize filter..."),0); + + for (Q_INT32 y = rect.y(); y < rect.height(); y++) + { + Q_INT32 x = rect.x(); + Q_INT32 x0 = rect.x(); + Q_INT32 y0 = rect.x(); + Q_INT32 width = rect.width(); + Q_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(QWidget* parent, KisPaintDeviceSP /*dev*/) +{ + vKisIntegerWidgetParam param; + param.push_back( KisIntegerWidgetParam( 2, 100, 30, i18n("Radius"), "radius" ) ); + return new KisMultiIntegerFilterWidget(parent, id().id().ascii(), id().id().ascii(), param ); +} + +KisFilterConfiguration* KisRoundCornersFilter::configuration(QWidget* nwidget) +{ + KisMultiIntegerFilterWidget* widget = (KisMultiIntegerFilterWidget*) nwidget; + if( widget == 0 ) + { + return new KisRoundCornersFilterConfiguration( 30 ); + } else { + return new KisRoundCornersFilterConfiguration( widget->valueAt( 0 ) ); + } +} diff --git a/krita/plugins/filters/roundcorners/kis_round_corners_filter.h b/krita/plugins/filters/roundcorners/kis_round_corners_filter.h new file mode 100644 index 00000000..2b965b5d --- /dev/null +++ b/krita/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(Q_INT32 radius) + : KisFilterConfiguration( "roundcorners", 1 ) + { + setProperty("radius", radius); + }; +public: + inline Q_INT32 radius() { return getInt("radius"); }; +}; + +class KisRoundCornersFilter : public KisFilter +{ +public: + KisRoundCornersFilter(); +public: + virtual void process(KisPaintDeviceSP,KisPaintDeviceSP, KisFilterConfiguration* , const QRect&); + 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(QWidget* parent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(QWidget*); + virtual KisFilterConfiguration * configuration() { return new KisRoundCornersFilterConfiguration( 30 ); }; +private: +}; + +#endif diff --git a/krita/plugins/filters/roundcorners/kis_round_corners_filter_plugin.cc b/krita/plugins/filters/roundcorners/kis_round_corners_filter_plugin.cc new file mode 100644 index 00000000..c21be444 --- /dev/null +++ b/krita/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( kritaroundcornersfilter, KisRoundCornersFilterPluginFactory( "krita" ) ) + +KisRoundCornersFilterPlugin::KisRoundCornersFilterPlugin(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(KisRoundCornersFilterPluginFactory::instance()); + + if (parent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(parent); + manager->add(new KisRoundCornersFilter()); + } +} + +KisRoundCornersFilterPlugin::~KisRoundCornersFilterPlugin() +{ +} + diff --git a/krita/plugins/filters/roundcorners/kis_round_corners_filter_plugin.h b/krita/plugins/filters/roundcorners/kis_round_corners_filter_plugin.h new file mode 100644 index 00000000..cb82b9fb --- /dev/null +++ b/krita/plugins/filters/roundcorners/kis_round_corners_filter_plugin.h @@ -0,0 +1,32 @@ +/* + * This file is part of Krita + * + * 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(QObject *parent, const char *name, const QStringList &); + virtual ~KisRoundCornersFilterPlugin(); +}; + +#endif diff --git a/krita/plugins/filters/roundcorners/kritaroundcornersfilter.desktop b/krita/plugins/filters/roundcorners/kritaroundcornersfilter.desktop new file mode 100644 index 00000000..576a02b4 --- /dev/null +++ b/krita/plugins/filters/roundcorners/kritaroundcornersfilter.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=Krita/Filter +Type=Service +X-KDE-Library=kritaroundcornersfilter +X-Krita-Version=2 diff --git a/krita/plugins/filters/smalltilesfilter/Makefile.am b/krita/plugins/filters/smalltilesfilter/Makefile.am new file mode 100644 index 00000000..7c62bb1d --- /dev/null +++ b/krita/plugins/filters/smalltilesfilter/Makefile.am @@ -0,0 +1,22 @@ +kde_services_DATA = kritasmalltilesfilter.desktop + +INCLUDES = \ + -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../ui \ + -I$(srcdir)/../../../../lib/kofficecore \ + $(all_includes) + +kde_module_LTLIBRARIES = kritasmalltilesfilter.la + +kritasmalltilesfilter_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 + +kritasmalltilesfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritasmalltilesfilter_la_LIBADD = ../../../libkritacommon.la + +kritasmalltilesfilter_la_METASOURCES = AUTO diff --git a/krita/plugins/filters/smalltilesfilter/kis_small_tiles_filter.cc b/krita/plugins/filters/smalltilesfilter/kis_small_tiles_filter.cc new file mode 100644 index 00000000..541a5ab2 --- /dev/null +++ b/krita/plugins/filters/smalltilesfilter/kis_small_tiles_filter.cc @@ -0,0 +1,187 @@ +/* + * This file is part of Krita + * + * 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 QString & s) +{ + KisFilterConfiguration::fromXML(s); + m_numberOfTiles = getInt("numberOfTiles"); +} + +QString 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 QRect& rect) +{ + //read the filter configuration values from the KisFilterConfiguration object + Q_UINT32 numberOfTiles = ((KisSmallTilesFilterConfiguration*)configuration)->numberOfTiles(); + + createSmallTiles(src, dst, rect, numberOfTiles); +} + +void KisSmallTilesFilter::createSmallTiles(KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect& rect, Q_UINT32 numberOfTiles) +{ + if (!src) return; + if (!dst) return; + + QRect 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(); + +// QRect tmpRect = tmp->exactBounds(); +// +// for( Q_UINT32 i=0; i < numberOfTiles; i++ ) +// { +// for( Q_UINT32 j=0; j < numberOfTiles; j++ ) +// { +// for( Q_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(QWidget* parent, KisPaintDeviceSP /*dev*/) +{ + vKisIntegerWidgetParam param; + param.push_back( KisIntegerWidgetParam( 2, 5, 1, i18n("Number of tiles"), "smalltiles" ) ); + return new KisMultiIntegerFilterWidget(parent, id().id().ascii(), id().id().ascii(), param ); +} + +KisFilterConfiguration* KisSmallTilesFilter::configuration(QWidget* nwidget) +{ + KisMultiIntegerFilterWidget* widget = (KisMultiIntegerFilterWidget*) nwidget; + if( widget == 0 ) + { + return new KisSmallTilesFilterConfiguration( 2 ); + } else { + return new KisSmallTilesFilterConfiguration( widget->valueAt( 0 ) ); + } +} diff --git a/krita/plugins/filters/smalltilesfilter/kis_small_tiles_filter.h b/krita/plugins/filters/smalltilesfilter/kis_small_tiles_filter.h new file mode 100644 index 00000000..41346a1e --- /dev/null +++ b/krita/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(Q_UINT32 numberOfTiles) + : KisFilterConfiguration( "smalltiles", 1 ) + , m_numberOfTiles(numberOfTiles) {}; + + + virtual void fromXML( const QString& ); + virtual QString toString(); + +public: + inline Q_UINT32 numberOfTiles() { return m_numberOfTiles; }; + +private: + Q_UINT32 m_numberOfTiles; +}; + +class KisSmallTilesFilter : public KisFilter +{ + +public: + KisSmallTilesFilter(); + +public: + virtual void process(KisPaintDeviceSP,KisPaintDeviceSP, KisFilterConfiguration* , const QRect&); + 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(QWidget* parent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration * configuration(QWidget*); + virtual KisFilterConfiguration * configuration() { return new KisSmallTilesFilterConfiguration( 2 ); }; + +private: + void createSmallTiles(KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect& rect, Q_UINT32 numberOfTiles); +}; + +#endif diff --git a/krita/plugins/filters/smalltilesfilter/kis_small_tiles_filter_plugin.cc b/krita/plugins/filters/smalltilesfilter/kis_small_tiles_filter_plugin.cc new file mode 100644 index 00000000..6c51632c --- /dev/null +++ b/krita/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( kritasmalltilesfilter, KisSmallTilesFilterPluginFactory( "krita" ) ) + +KisSmallTilesFilterPlugin::KisSmallTilesFilterPlugin(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(KisSmallTilesFilterPluginFactory::instance()); + + if (parent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(parent); + manager->add(new KisSmallTilesFilter()); + } +} + +KisSmallTilesFilterPlugin::~KisSmallTilesFilterPlugin() +{ +} + diff --git a/krita/plugins/filters/smalltilesfilter/kis_small_tiles_filter_plugin.h b/krita/plugins/filters/smalltilesfilter/kis_small_tiles_filter_plugin.h new file mode 100644 index 00000000..f26fc155 --- /dev/null +++ b/krita/plugins/filters/smalltilesfilter/kis_small_tiles_filter_plugin.h @@ -0,0 +1,32 @@ +/* + * This file is part of Krita + * + * 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(QObject *parent, const char *name, const QStringList &); + virtual ~KisSmallTilesFilterPlugin(); +}; + +#endif diff --git a/krita/plugins/filters/smalltilesfilter/kritasmalltilesfilter.desktop b/krita/plugins/filters/smalltilesfilter/kritasmalltilesfilter.desktop new file mode 100644 index 00000000..8c518c7f --- /dev/null +++ b/krita/plugins/filters/smalltilesfilter/kritasmalltilesfilter.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=Krita/Filter +Type=Service +X-KDE-Library=kritasmalltilesfilter +X-Krita-Version=2 diff --git a/krita/plugins/filters/sobelfilter/Makefile.am b/krita/plugins/filters/sobelfilter/Makefile.am new file mode 100644 index 00000000..c83e1c7d --- /dev/null +++ b/krita/plugins/filters/sobelfilter/Makefile.am @@ -0,0 +1,22 @@ +kde_services_DATA = kritasobelfilter.desktop + +INCLUDES = \ + -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = kritasobelfilter.la + +kritasobelfilter_la_SOURCES = kis_sobel_filter_plugin.cc \ + kis_sobel_filter.cc + +noinst_HEADERS = kis_sobel_filter_plugin.h \ + kis_sobel_filter.h + +kritasobelfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritasobelfilter_la_LIBADD = ../../../libkritacommon.la + +kritasobelfilter_la_METASOURCES = AUTO diff --git a/krita/plugins/filters/sobelfilter/kis_sobel_filter.cc b/krita/plugins/filters/sobelfilter/kis_sobel_filter.cc new file mode 100644 index 00000000..122887b4 --- /dev/null +++ b/krita/plugins/filters/sobelfilter/kis_sobel_filter.cc @@ -0,0 +1,217 @@ +/* + * This file is part of Krita + * + * 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 QString & s) +{ + KisFilterConfiguration::fromXML(s); + m_doHorizontally = getBool( "doHorizontally" ); + m_doVertically = getBool( "doVertically" ); + m_keepSign = getBool( "makeOpaque" ); +} + +QString 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 QRect& 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, Q_UINT8* data, Q_UINT32 x, Q_UINT32 y, Q_UINT32 w, Q_UINT32 h) +{ + if (y > h -1) y = h -1; + Q_UINT32 pixelSize = src->pixelSize(); + + src->readBytes( data, x, y, w, 1 ); + + for (Q_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 QRect & rc, KisPaintDeviceSP src, KisPaintDeviceSP dst, bool doHorizontal, bool doVertical, bool keepSign, bool makeOpaque) +{ + QRect rect = rc; //src->exactBounds(); + Q_UINT32 x = rect.x(); + Q_UINT32 y = rect.y(); + Q_UINT32 width = rect.width(); + Q_UINT32 height = rect.height(); + Q_UINT32 pixelSize = src->pixelSize(); + + setProgressTotalSteps( height ); + setProgressStage(i18n("Applying sobel filter..."),0); + + /* allocate row buffers */ + Q_UINT8* prevRow = new Q_UINT8[ (width + 2) * pixelSize]; + Q_CHECK_PTR(prevRow); + Q_UINT8* curRow = new Q_UINT8[ (width + 2) * pixelSize]; + Q_CHECK_PTR(curRow); + Q_UINT8* nextRow = new Q_UINT8[ (width + 2) * pixelSize]; + Q_CHECK_PTR(nextRow); + Q_UINT8* dest = new Q_UINT8[ width * pixelSize]; + Q_CHECK_PTR(dest); + + Q_UINT8* pr = prevRow + pixelSize; + Q_UINT8* cr = curRow + pixelSize; + Q_UINT8* nr = nextRow + pixelSize; + + prepareRow (src, pr, x, y - 1, width, height); + prepareRow (src, cr, x, y, width, height); + + Q_UINT32 counter =0; + Q_UINT8* d; + Q_UINT8* tmp; + Q_INT32 gradient, horGradient, verGradient; + // loop through the rows, applying the sobel convolution + for (Q_UINT32 row = 0; row < height; row++) + { + + // prepare the next row + prepareRow (src, nr, x, row + 1, width, height); + d = dest; + + for (Q_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 = (Q_INT32)((doVertical && doHorizontal) ? + (ROUND (RMS (horGradient, verGradient)) / 5.66) // always >0 + : (keepSign ? (127 + (ROUND ((horGradient + verGradient) / 8.0))) + : (ROUND (QABS (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(QWidget* parent, 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(parent, id().id().ascii(), id().id().ascii(), param ); +} + +KisFilterConfiguration* KisSobelFilter::configuration(QWidget* 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/krita/plugins/filters/sobelfilter/kis_sobel_filter.h b/krita/plugins/filters/sobelfilter/kis_sobel_filter.h new file mode 100644 index 00000000..9127cd3a --- /dev/null +++ b/krita/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 QString& ); + virtual QString 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 QRect&); + 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(QWidget* parent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(QWidget*); + virtual KisFilterConfiguration * configuration() { return new KisSobelFilterConfiguration( true, true, true, true); }; +private: + void prepareRow (KisPaintDeviceSP src, Q_UINT8* data, Q_UINT32 x, Q_UINT32 y, Q_UINT32 w, Q_UINT32 h); + void sobel(const QRect & rc, KisPaintDeviceSP src, KisPaintDeviceSP dst, bool doHorizontal, bool doVertical, bool keepSign, bool makeOpaque); +}; + +#endif diff --git a/krita/plugins/filters/sobelfilter/kis_sobel_filter_plugin.cc b/krita/plugins/filters/sobelfilter/kis_sobel_filter_plugin.cc new file mode 100644 index 00000000..cc3b31b1 --- /dev/null +++ b/krita/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( kritasobelfilter, KisSobelFilterPluginFactory( "krita" ) ) + +KisSobelFilterPlugin::KisSobelFilterPlugin(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(KisSobelFilterPluginFactory::instance()); + + if (parent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(parent); + manager->add(new KisSobelFilter()); + } +} + +KisSobelFilterPlugin::~KisSobelFilterPlugin() +{ +} + diff --git a/krita/plugins/filters/sobelfilter/kis_sobel_filter_plugin.h b/krita/plugins/filters/sobelfilter/kis_sobel_filter_plugin.h new file mode 100644 index 00000000..95a80905 --- /dev/null +++ b/krita/plugins/filters/sobelfilter/kis_sobel_filter_plugin.h @@ -0,0 +1,32 @@ +/* + * This file is part of Krita + * + * 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(QObject *parent, const char *name, const QStringList &); + virtual ~KisSobelFilterPlugin(); +}; + +#endif diff --git a/krita/plugins/filters/sobelfilter/kritasobelfilter.desktop b/krita/plugins/filters/sobelfilter/kritasobelfilter.desktop new file mode 100644 index 00000000..2bc0debd --- /dev/null +++ b/krita/plugins/filters/sobelfilter/kritasobelfilter.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=Krita/Filter +Type=Service +X-KDE-Library=kritasobelfilter +X-Krita-Version=2 diff --git a/krita/plugins/filters/threadtest/Makefile.am b/krita/plugins/filters/threadtest/Makefile.am new file mode 100644 index 00000000..c176720c --- /dev/null +++ b/krita/plugins/filters/threadtest/Makefile.am @@ -0,0 +1,18 @@ +kde_services_DATA = kritathreadtest.desktop + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + -I$(srcdir)/../../../../lib/kofficecore \ + $(all_includes) + +kritathreadtest_la_SOURCES = threadtest.cc + +kde_module_LTLIBRARIES = kritathreadtest.la +noinst_HEADERS = threadtest.h + +kritathreadtest_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritathreadtest_la_LIBADD = ../../../libkritacommon.la + +kritathreadtest_la_METASOURCES = AUTO diff --git a/krita/plugins/filters/threadtest/kritathreadtest.desktop b/krita/plugins/filters/threadtest/kritathreadtest.desktop new file mode 100644 index 00000000..04c66730 --- /dev/null +++ b/krita/plugins/filters/threadtest/kritathreadtest.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=Krita/Filter +Type=Service +X-KDE-Library=kritathreadtest +X-Krita-Version=2 diff --git a/krita/plugins/filters/threadtest/threadtest.cc b/krita/plugins/filters/threadtest/threadtest.cc new file mode 100644 index 00000000..f965b7f3 --- /dev/null +++ b/krita/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 KritaThreadTestFactory; +K_EXPORT_COMPONENT_FACTORY( kritathreadtest, KritaThreadTestFactory( "krita" ) ) + +KritaThreadTest::KritaThreadTest(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(KritaThreadTestFactory::instance()); + + if (parent->inherits("KisFilterRegistry")) { + KisFilterRegistry * r = dynamic_cast(parent); + r->add(new KisFilterInvert()); + } +} + +KritaThreadTest::~KritaThreadTest() +{ +} + +class InversionThread : public QThread +{ + +public: + + InversionThread(const QString & name, KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect& rect) + : QThread() + , m_name(name) + , m_src(src) + , m_dst(dst) + , m_rect(rect) + { + kdDebug() << "Thread created " << m_name << ", " << QThread::currentThread() << ", " << m_rect << "\n"; + }; + + void run() + { + kdDebug() << "Thread started:" << m_name << ", " << QThread::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); + Q_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] = Q_UINT8_MAX - srcIt.oldRawData()[i]; + } + } + ++srcIt; + ++dstIt; + } + kdDebug() << "Thread " << m_name << " finished \n"; + }; + +private: + QString m_name; + KisPaintDeviceSP m_src; + KisPaintDeviceSP m_dst; + QRect m_rect; + +}; + +KisFilterInvert::KisFilterInvert() : KisFilter(id(), "colors", i18n("Invert with &Threads")) +{ +} + +void KisFilterInvert::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* /*config*/, const QRect& rect) +{ + kdDebug() << "Going to invert " << rect << "\n"; + int h2 = rect.height() / 2; + int w2 = rect.width() / 2; + + setProgressTotalSteps(4); + InversionThread t1("t1", src, dst, QRect(0, 0, w2, h2)); + InversionThread t2("t2", src, dst, QRect(w2, 0, w2, h2)); + InversionThread t3("t3", src, dst, QRect(0, h2, w2, h2)); + InversionThread t4("t4", src, dst, QRect(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/krita/plugins/filters/threadtest/threadtest.h b/krita/plugins/filters/threadtest/threadtest.h new file mode 100644 index 00000000..da3ff44e --- /dev/null +++ b/krita/plugins/filters/threadtest/threadtest.h @@ -0,0 +1,46 @@ +/* + * This file is part of Krita + * + * 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 KritaThreadTest : public KParts::Plugin +{ +public: + KritaThreadTest(QObject *parent, const char *name, const QStringList &); + virtual ~KritaThreadTest(); +}; + +class KisFilterInvert : public KisFilter +{ +public: + KisFilterInvert(); +public: + virtual void process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration*, const QRect&); + 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/krita/plugins/filters/unsharp/Makefile.am b/krita/plugins/filters/unsharp/Makefile.am new file mode 100644 index 00000000..5eabc3e8 --- /dev/null +++ b/krita/plugins/filters/unsharp/Makefile.am @@ -0,0 +1,19 @@ +kritarcdir = $(kde_datadir)/krita/kritaplugins + +kde_services_DATA = kritaunsharpfilter.desktop + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kritaunsharpfilter_la_SOURCES = wdgunsharp.ui kis_wdg_unsharp.cc unsharp.cc kis_unsharp_filter.cc + +kde_module_LTLIBRARIES = kritaunsharpfilter.la + +kritaunsharpfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritaunsharpfilter_la_LIBADD = ../../../libkritacommon.la + +METASOURCES = AUTO diff --git a/krita/plugins/filters/unsharp/kis_unsharp_filter.cc b/krita/plugins/filters/unsharp/kis_unsharp_filter.cc new file mode 100644 index 00000000..aeecd7db --- /dev/null +++ b/krita/plugins/filters/unsharp/kis_unsharp_filter.cc @@ -0,0 +1,152 @@ +/* + * This file is part of Krita + * + * 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 kernelFromQImage(const QImage& 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 Q_INT32[count]; + Q_INT32* itData = k->data; + Q_UINT8* itImg = 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(QWidget* parent, KisPaintDeviceSP ) +{ + return new KisWdgUnsharp(this, parent, "configuration of color to alpha"); +} + +KisFilterConfiguration* KisUnsharpFilter::configuration(QWidget* 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 QRect& rect) +{ + Q_ASSERT(src != 0); + Q_ASSERT(dst != 0); + + setProgressTotalSteps(rect.width() * rect.height()); + + if(!config) config = new KisFilterConfiguration(id().id(), 1); + + QVariant 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); + + QImage mask; + kas->createBrush(&mask); + + KisKernelSP kernel = kernelFromQImage(mask); // TODO: for 1.6 reuse the krita's core function for creating kernel : KisKernel::fromQImage + + 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); + + Q_UINT8 *colors[2]; + + int pixelsProcessed = 0; + Q_INT32 weights[2]; +/* weights[0] = 128; + Q_INT32 factor = (Q_UINT32) 128 / amount; + weights[1] = (factor - 128);*/ + Q_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()) + { + Q_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/krita/plugins/filters/unsharp/kis_unsharp_filter.h b/krita/plugins/filters/unsharp/kis_unsharp_filter.h new file mode 100644 index 00000000..3b1dc882 --- /dev/null +++ b/krita/plugins/filters/unsharp/kis_unsharp_filter.h @@ -0,0 +1,47 @@ +/* + * This file is part of Krita + * + * 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 QRect&); + static inline KisID id() { return KisID("unsharpmask", 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(QWidget* parent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(QWidget*); +}; + +#endif diff --git a/krita/plugins/filters/unsharp/kis_wdg_unsharp.cc b/krita/plugins/filters/unsharp/kis_wdg_unsharp.cc new file mode 100644 index 00000000..101d5601 --- /dev/null +++ b/krita/plugins/filters/unsharp/kis_wdg_unsharp.cc @@ -0,0 +1,52 @@ +/* + * This file is part of Krita + * + * 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* , QWidget * parent, const char * name) : KisFilterConfigWidget ( parent, name ) +{ + QGridLayout *widgetLayout = new QGridLayout(this, 1, 1); + m_widget = new WdgUnsharp(this); + widgetLayout -> addWidget(m_widget,0,0); + + connect( widget()->intHalfSize, SIGNAL( valueChanged(int)), SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->doubleAmount, SIGNAL( valueChanged(double)), SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->intThreshold, SIGNAL( valueChanged(int)), SIGNAL(sigPleaseUpdatePreview())); +} + +void KisWdgUnsharp::setConfiguration(KisFilterConfiguration* config) +{ + QVariant 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/krita/plugins/filters/unsharp/kis_wdg_unsharp.h b/krita/plugins/filters/unsharp/kis_wdg_unsharp.h new file mode 100644 index 00000000..1c4fd560 --- /dev/null +++ b/krita/plugins/filters/unsharp/kis_wdg_unsharp.h @@ -0,0 +1,44 @@ +/* + * This file is part of Krita + * + * 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 + public: + KisWdgUnsharp( KisFilter* nfilter, QWidget * parent, const char * name); + inline WdgUnsharp* widget() { return m_widget; }; + virtual void setConfiguration(KisFilterConfiguration*); + private: + WdgUnsharp* m_widget; +}; + +#endif diff --git a/krita/plugins/filters/unsharp/kritaunsharpfilter.desktop b/krita/plugins/filters/unsharp/kritaunsharpfilter.desktop new file mode 100644 index 00000000..5b0f02f7 --- /dev/null +++ b/krita/plugins/filters/unsharp/kritaunsharpfilter.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=Krita/Filter +Type=Service +X-KDE-Library=kritaunsharpfilter +X-Krita-Version=2 diff --git a/krita/plugins/filters/unsharp/unsharp.cc b/krita/plugins/filters/unsharp/unsharp.cc new file mode 100644 index 00000000..15170eff --- /dev/null +++ b/krita/plugins/filters/unsharp/unsharp.cc @@ -0,0 +1,50 @@ +/* + * This file is part of Krita + * + * 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( kritaunsharpfilter, UnsharpPluginFactory( "krita" ) ) + +UnsharpPlugin::UnsharpPlugin(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(UnsharpPluginFactory::instance()); + + + kdDebug(41006) << "Extensions Image enhancement Filters plugin. Class: " + << className() + << ", Parent: " + << parent -> className() + << "\n"; + + if (parent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(parent); + manager->add(new KisUnsharpFilter()); + } +} + +UnsharpPlugin::~UnsharpPlugin() +{ +} diff --git a/krita/plugins/filters/unsharp/unsharp.h b/krita/plugins/filters/unsharp/unsharp.h new file mode 100644 index 00000000..410b7568 --- /dev/null +++ b/krita/plugins/filters/unsharp/unsharp.h @@ -0,0 +1,37 @@ +/* + * This file is part of Krita + * + * 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(QObject *parent, const char *name, const QStringList &); + virtual ~UnsharpPlugin(); +}; + +#endif diff --git a/krita/plugins/filters/unsharp/wdgunsharp.ui b/krita/plugins/filters/unsharp/wdgunsharp.ui new file mode 100644 index 00000000..1acaadab --- /dev/null +++ b/krita/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/krita/plugins/filters/wavefilter/Makefile.am b/krita/plugins/filters/wavefilter/Makefile.am new file mode 100644 index 00000000..66f6bf54 --- /dev/null +++ b/krita/plugins/filters/wavefilter/Makefile.am @@ -0,0 +1,22 @@ +kritarcdir = $(kde_datadir)/krita/kritaplugins + +kde_services_DATA = kritawavefilter.desktop + + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kritawavefilter_la_SOURCES = wavefilter.cc wdgwaveoptions.ui \ + kis_wdg_wave.cpp + +kde_module_LTLIBRARIES = kritawavefilter.la +noinst_HEADERS = wavefilter.h kis_wdg_wave.h + +kritawavefilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritawavefilter_la_LIBADD = ../../../libkritacommon.la + +METASOURCES = AUTO diff --git a/krita/plugins/filters/wavefilter/kis_wdg_wave.cpp b/krita/plugins/filters/wavefilter/kis_wdg_wave.cpp new file mode 100644 index 00000000..bcc47103 --- /dev/null +++ b/krita/plugins/filters/wavefilter/kis_wdg_wave.cpp @@ -0,0 +1,90 @@ +/* + * This file is part of Krita + * + * 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*/, QWidget* parent, const char* name) + : KisFilterConfigWidget(parent,name) +{ + QGridLayout *widgetLayout = new QGridLayout(this, 1, 1); + m_widget = new WdgWaveOptions(this); + widgetLayout -> addWidget(m_widget, 0, 0); + + connect( widget()->intHWavelength, SIGNAL( valueChanged(int)), SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->intHShift, SIGNAL( valueChanged(int)), SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->intHAmplitude, SIGNAL( valueChanged(int)), SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->cbHShape, SIGNAL( activated(int)), SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->intVWavelength, SIGNAL( valueChanged(int)), SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->intVShift, SIGNAL( valueChanged(int)), SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->intVAmplitude, SIGNAL( valueChanged(int)), SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->cbVShape, SIGNAL( activated(int)), SIGNAL(sigPleaseUpdatePreview())); +} + +KisWdgWave::~KisWdgWave() +{ +} + +void KisWdgWave::setConfiguration(KisFilterConfiguration* config) +{ + QVariant 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("horizontalshape", 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("verticalshape", value)) + { + widget()->cbVShape->setCurrentItem( value.toUInt() ); + } +} + + +#include "kis_wdg_wave.moc" + diff --git a/krita/plugins/filters/wavefilter/kis_wdg_wave.h b/krita/plugins/filters/wavefilter/kis_wdg_wave.h new file mode 100644 index 00000000..e71082d1 --- /dev/null +++ b/krita/plugins/filters/wavefilter/kis_wdg_wave.h @@ -0,0 +1,43 @@ +/* + * This file is part of Krita + * + * 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 + public: + KisWdgWave(KisFilter* nfilter, QWidget* parent = 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/krita/plugins/filters/wavefilter/kritawavefilter.desktop b/krita/plugins/filters/wavefilter/kritawavefilter.desktop new file mode 100644 index 00000000..0fbd73bf --- /dev/null +++ b/krita/plugins/filters/wavefilter/kritawavefilter.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=Krita/Filter +Type=Service +X-KDE-Library=kritawavefilter +X-Krita-Version=2 diff --git a/krita/plugins/filters/wavefilter/wavefilter.cc b/krita/plugins/filters/wavefilter/wavefilter.cc new file mode 100644 index 00000000..af6332bb --- /dev/null +++ b/krita/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 KritaWaveFilterFactory; +K_EXPORT_COMPONENT_FACTORY( kritawavefilter, KritaWaveFilterFactory( "krita" ) ) + +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; +}; + + + +KritaWaveFilter::KritaWaveFilter(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(KritaWaveFilterFactory::instance()); + + + if (parent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(parent); + manager->add(new KisFilterWave()); + } +} + +KritaWaveFilter::~KritaWaveFilter() +{ +} + +KisFilterWave::KisFilterWave() : KisFilter(id(), "other", i18n("&Wave...")) +{ +} + +KisFilterConfiguration* KisFilterWave::configuration(QWidget* 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("horizontalshape", 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("verticalshape", wN->widget()->cbVShape->currentItem() ); + } + return config; +} + +KisFilterConfigWidget * KisFilterWave::createConfigurationWidget(QWidget* parent, KisPaintDeviceSP /*dev*/) +{ + return new KisWdgWave((KisFilter*)this, (QWidget*)parent, i18n("Configuration of wave filter").ascii()); +} + +void KisFilterWave::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* config, const QRect& rect) +{ + Q_ASSERT(src != 0); + Q_ASSERT(dst != 0); + + setProgressTotalSteps(rect.width() * rect.height()); + + QVariant 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 horizontalshape = (config && config->getProperty("horizontalshape", 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 verticalshape = (config && config->getProperty("verticalshape", value)) ? value.toInt() : 0; + KisRectIteratorPixel dstIt = dst->createRectIterator(rect.x(), rect.y(), rect.width(), rect.height(), true ); + KisWaveCurve* verticalcurve; + if(verticalshape == 1) + verticalcurve = new KisTriangleWaveCurve(verticalamplitude, verticalwavelength, verticalshift); + else + verticalcurve = new KisSinusoidalWaveCurve(verticalamplitude, verticalwavelength, verticalshift); + KisWaveCurve* horizontalcurve; + if(horizontalshape == 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/krita/plugins/filters/wavefilter/wavefilter.h b/krita/plugins/filters/wavefilter/wavefilter.h new file mode 100644 index 00000000..1eb49c11 --- /dev/null +++ b/krita/plugins/filters/wavefilter/wavefilter.h @@ -0,0 +1,53 @@ +/* + * This file is part of Krita + * + * 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 KritaWaveFilter : public KParts::Plugin +{ +public: + KritaWaveFilter(QObject *parent, const char *name, const QStringList &); + virtual ~KritaWaveFilter(); +}; + +class KisFilterWave : public KisFilter +{ + public: + KisFilterWave(); + public: + virtual void process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration*, const QRect&); + 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(QWidget* parent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(QWidget*); +}; + +#endif diff --git a/krita/plugins/filters/wavefilter/wdgwaveoptions.ui b/krita/plugins/filters/wavefilter/wdgwaveoptions.ui new file mode 100644 index 00000000..e6bb0416 --- /dev/null +++ b/krita/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/krita/plugins/paintops/Makefile.am b/krita/plugins/paintops/Makefile.am new file mode 100644 index 00000000..328f0162 --- /dev/null +++ b/krita/plugins/paintops/Makefile.am @@ -0,0 +1,2 @@ +SUBDIRS = \ + defaultpaintops diff --git a/krita/plugins/paintops/defaultpaintops/Makefile.am b/krita/plugins/paintops/defaultpaintops/Makefile.am new file mode 100644 index 00000000..5a52d651 --- /dev/null +++ b/krita/plugins/paintops/defaultpaintops/Makefile.am @@ -0,0 +1,38 @@ +kritaimagesdir = $(prefix)/share/apps/krita/images + +kritaimages_DATA = \ + airbrush.png \ + paintbrush.png \ + eraser.png \ + pencil.png + + +kde_services_DATA = kritadefaultpaintops.desktop + +# all_includes must remain last! +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) $(KOPAINTER_INCLUDES) $(all_includes) + + +kritadefaultpaintops_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 = kritadefaultpaintops.la + +kritadefaultpaintops_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritadefaultpaintops_la_LIBADD = ../../../libkritacommon.la $(LIB_KOPAINTER) $(LIB_KOFFICECORE) + +kritadefaultpaintops_la_METASOURCES = AUTO diff --git a/krita/plugins/paintops/defaultpaintops/README b/krita/plugins/paintops/defaultpaintops/README new file mode 100644 index 00000000..47b07ce7 --- /dev/null +++ b/krita/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/krita/plugins/paintops/defaultpaintops/airbrush.png b/krita/plugins/paintops/defaultpaintops/airbrush.png new file mode 100644 index 00000000..075fa49d Binary files /dev/null and b/krita/plugins/paintops/defaultpaintops/airbrush.png differ diff --git a/krita/plugins/paintops/defaultpaintops/defaultpaintops_plugin.cc b/krita/plugins/paintops/defaultpaintops/defaultpaintops_plugin.cc new file mode 100644 index 00000000..e23fd3cf --- /dev/null +++ b/krita/plugins/paintops/defaultpaintops/defaultpaintops_plugin.cc @@ -0,0 +1,70 @@ +/* + * defaultpaintops_plugin.cc -- Part of Krita + * + * 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( kritadefaultpaintops, DefaultPaintOpsPluginFactory( "kritacore" ) ) + + +DefaultPaintOpsPlugin::DefaultPaintOpsPlugin(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(DefaultPaintOpsPluginFactory::instance()); + + // This is not a gui plugin; only load it when the doc is created. + if ( parent->inherits("KisPaintOpRegistry") ) + { + KisPaintOpRegistry * r = dynamic_cast(parent); + // 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/krita/plugins/paintops/defaultpaintops/defaultpaintops_plugin.h b/krita/plugins/paintops/defaultpaintops/defaultpaintops_plugin.h new file mode 100644 index 00000000..402ae4a2 --- /dev/null +++ b/krita/plugins/paintops/defaultpaintops/defaultpaintops_plugin.h @@ -0,0 +1,35 @@ +/* + * 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 +public: + DefaultPaintOpsPlugin(QObject *parent, const char *name, const QStringList &); + virtual ~DefaultPaintOpsPlugin(); +}; + +#endif // DEFAULT_PAINTOPSGRAY_PLUGIN_H_ diff --git a/krita/plugins/paintops/defaultpaintops/eraser.png b/krita/plugins/paintops/defaultpaintops/eraser.png new file mode 100644 index 00000000..99eefc78 Binary files /dev/null and b/krita/plugins/paintops/defaultpaintops/eraser.png differ diff --git a/krita/plugins/paintops/defaultpaintops/kis_airbrushop.cc b/krita/plugins/paintops/defaultpaintops/kis_airbrushop.cc new file mode 100644 index 00000000..6f2e5cb1 --- /dev/null +++ b/krita/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 Krita took a brush +// shape -- often a simple ellipse -- and filled that shape with a +// random 'spray' of single pixels. +// +// Other, more advanced graphics apps, like the Gimp or Photoshop, +// take the brush shape 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 shapes, 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 shape -- 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; + + Q_INT32 x; + double xFraction; + Q_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 mask = brush->mask(info, xFraction, yFraction); + dab = computeDab(mask); + } + + m_painter->setDab(dab); // Cache dab for future paints in the painter. + m_painter->setPressure(info.pressure); // Cache pressure in the current painter. + + QRect dabRect = QRect(0, 0, brush->maskWidth(info), brush->maskHeight(info)); + QRect dstRect = QRect(x, y, dabRect.width(), dabRect.height()); + + KisImage * image = device->image(); + + if (image != 0) { + dstRect &= image->bounds(); + } + + if (dstRect.isNull() || dstRect.isEmpty() || !dstRect.isValid()) return; + + Q_INT32 sx = dstRect.x() - x; + Q_INT32 sy = dstRect.y() - y; + Q_INT32 sw = dstRect.width(); + Q_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/krita/plugins/paintops/defaultpaintops/kis_airbrushop.h b/krita/plugins/paintops/defaultpaintops/kis_airbrushop.h new file mode 100644 index 00000000..7e751d3e --- /dev/null +++ b/krita/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 QString 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/krita/plugins/paintops/defaultpaintops/kis_brushop.cc b/krita/plugins/paintops/defaultpaintops/kis_brushop.cc new file mode 100644 index 00000000..4a7485e5 --- /dev/null +++ b/krita/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(QWidget *parent) + : super(parent) +{ + m_optionsWidget = new QWidget(parent, "brush option widget"); + QHBoxLayout * l = new QHBoxLayout(m_optionsWidget); + l->setAutoAdd(true); + m_pressureVariation = new QLabel(i18n("Pressure variation: "), m_optionsWidget); + m_size = new QCheckBox(i18n("Size"), m_optionsWidget); + m_size->setChecked(true); + m_opacity = new QCheckBox(i18n("Opacity"), m_optionsWidget); + m_darken = new QCheckBox(i18n("Darken"), m_optionsWidget); + m_curveControl = new WdgBrushCurveControl(m_optionsWidget); + QToolButton* moreButton = new QToolButton(Qt::UpArrow, m_optionsWidget); + moreButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + moreButton->setMinimumSize(QSize(24,24)); // Bah, I had hoped the above line would make this unneeded + connect(moreButton, SIGNAL(clicked()), this, 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() == QDialog::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(QWidget * parent, const KisInputDevice& inputDevice) +{ + if (inputDevice == KisInputDevice::mouse()) { + // No options for mouse, only tablet devices + return 0; + } else { + return new KisBrushOpSettings(parent); + } +} + +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 == mask + // retrieve mask + // else if brush == image + // retrieve image + // subsample (mask | image) for position -- pos should be double! + // apply filters to mask (colour | gradient | pattern | etc. + // composite filtered mask 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. + Q_INT32 x; + double xFraction; + Q_INT32 y; + double yFraction; + + splitCoordinate(pt.x(), &x, &xFraction); + splitCoordinate(pt.y(), &y, &yFraction); + + KisPaintDeviceSP dab = 0; + + Q_UINT8 origOpacity = m_painter->opacity(); + KisColor origColor = m_painter->paintColor(); + + if (m_pressureOpacity) { + if (!m_customOpacity) + m_painter->setOpacity((Q_INT8)(origOpacity * info.pressure)); + else + m_painter->setOpacity((Q_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... + Q_UINT32 darkenAmount; + if (!m_customDarken) + darkenAmount = (Q_INT32)(255 - 75 * info.pressure); + else + darkenAmount = (Q_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 mask = brush->mask(adjustedInfo, xFraction, yFraction); + dab = computeDab(mask); + } + + m_painter->setPressure(adjustedInfo.pressure); + + QRect dabRect = QRect(0, 0, brush->maskWidth(adjustedInfo), + brush->maskHeight(adjustedInfo)); + QRect dstRect = QRect(x, y, dabRect.width(), dabRect.height()); + + KisImage * image = device->image(); + + if (image != 0) { + dstRect &= image->bounds(); + } + + if (dstRect.isNull() || dstRect.isEmpty() || !dstRect.isValid()) return; + + Q_INT32 sx = dstRect.x() - x; + Q_INT32 sy = dstRect.y() - y; + Q_INT32 sw = dstRect.width(); + Q_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/krita/plugins/paintops/defaultpaintops/kis_brushop.h b/krita/plugins/paintops/defaultpaintops/kis_brushop.h new file mode 100644 index 00000000..ecaf3ad2 --- /dev/null +++ b/krita/plugins/paintops/defaultpaintops/kis_brushop.h @@ -0,0 +1,112 @@ +/* + * 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 QWidget; +class QCheckBox; +class QLabel; +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 QString pixmap() { return "paintbrush.png"; } + virtual KisPaintOpSettings *settings(QWidget * parent, const KisInputDevice& inputDevice); +}; + +class KisBrushOpSettings : public QObject, public KisPaintOpSettings { + Q_OBJECT + typedef KisPaintOpSettings super; +public: + KisBrushOpSettings(QWidget *parent); + + 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 QWidget *widget() const { return m_optionsWidget; } +private slots: + void slotCustomCurves(); +private: + void transferCurve(KCurve* curve, double* target); + QWidget *m_optionsWidget; + QLabel * m_pressureVariation; + QCheckBox * m_size; + QCheckBox * m_opacity; + QCheckBox * 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/krita/plugins/paintops/defaultpaintops/kis_convolveop.cc b/krita/plugins/paintops/defaultpaintops/kis_convolveop.cc new file mode 100644 index 00000000..ae55f54f --- /dev/null +++ b/krita/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/krita/plugins/paintops/defaultpaintops/kis_convolveop.h b/krita/plugins/paintops/defaultpaintops/kis_convolveop.h new file mode 100644 index 00000000..d5dc3764 --- /dev/null +++ b/krita/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/krita/plugins/paintops/defaultpaintops/kis_dlgbrushcurvecontrol.ui b/krita/plugins/paintops/defaultpaintops/kis_dlgbrushcurvecontrol.ui new file mode 100644 index 00000000..7682c12f --- /dev/null +++ b/krita/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 + + + + layout4 + + + + unnamed + + + + sizeCheckbox + + + Use custom curve + + + + + sizeCurve + + + + 7 + 7 + 0 + 0 + + + + + + + + + + Widget9 + + + Opacity Curve + + + + unnamed + + + + layout3 + + + + unnamed + + + + opacityCheckbox + + + Use custom curve + + + + + opacityCurve + + + + 7 + 7 + 0 + 0 + + + + + + + + + + TabPage + + + Darken Curve + + + + unnamed + + + + layout5 + + + + 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/krita/plugins/paintops/defaultpaintops/kis_duplicateop.cc b/krita/plugins/paintops/defaultpaintops/kis_duplicateop.cc new file mode 100644 index 00000000..79d00b96 --- /dev/null +++ b/krita/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. + Q_INT32 x; + double xFraction; + Q_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 mask = brush->mask(info, xFraction, yFraction); + dab = computeDab(mask, KisMetaRegistry::instance()->csRegistry()->getAlpha8()); + } + + m_painter->setPressure(info.pressure); + + KisPoint srcPointF = pt - m_painter->duplicateOffset(); + QPoint srcPoint = QPoint(x - static_cast(m_painter->duplicateOffset().x()), + y - static_cast(m_painter->duplicateOffset().y())); + + + Q_INT32 sw = dab->extent().width(); + Q_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())); + QRect r = QRect(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) + { + Q_UINT16 dataDevice[4]; + Q_UINT16 dataSrcDev[4]; + QMemArray 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(), (Q_UINT8*)dataDevice, 1); + deviceCs->toLabA16(srcDevIt.rawData(), (Q_UINT8*)dataSrcDev, 1); + // Division + for( int k = 0; k < 3; k++) + { + matrixIt[k] = dataDevice[k] / (double)QMAX(dataSrcDev [k], 1); + } + ++deviceIt; + ++srcDevIt; + matrixIt +=3; + } + deviceIt.nextRow(); + srcDevIt.nextRow(); + } + // Minimize energy + { + int iter = 0; + double err; + QMemArray 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(), (Q_UINT8*)dataDevice, 1); + deviceCs->toLabA16(srcDevIt.rawData(), (Q_UINT8*)dataSrcDev, 1); + // Multiplication + for( int k = 0; k < 3; k++) + { + dataSrcDev[k] = (int)CLAMP( matrixIt[k] * QMAX( dataSrcDev[k], 1), 0, 65535 ); + } + deviceCs->fromLabA16((Q_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(); + + QRect dabRect = QRect(0, 0, brush->maskWidth(info), brush->maskHeight(info)); + QRect dstRect = QRect(x, y, dabRect.width(), dabRect.height()); + + KisImage * image = device->image(); + + if (image != 0) { + dstRect &= image->bounds(); + } + + if (dstRect.isNull() || dstRect.isEmpty() || !dstRect.isValid()) return; + + Q_INT32 sx = dstRect.x() - x; + Q_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/krita/plugins/paintops/defaultpaintops/kis_duplicateop.h b/krita/plugins/paintops/defaultpaintops/kis_duplicateop.h new file mode 100644 index 00000000..965e0dc9 --- /dev/null +++ b/krita/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/krita/plugins/paintops/defaultpaintops/kis_eraseop.cc b/krita/plugins/paintops/defaultpaintops/kis_eraseop.cc new file mode 100644 index 00000000..4fe46af2 --- /dev/null +++ b/krita/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 Krita 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; + + Q_INT32 destX; + double xFraction; + Q_INT32 destY; + double yFraction; + + splitCoordinate(pt.x(), &destX, &xFraction); + splitCoordinate(pt.y(), &destY, &yFraction); + + KisAlphaMaskSP mask = brush->mask(info, xFraction, yFraction); + + KisPaintDeviceSP dab = new KisPaintDevice(device->colorSpace(), "erase op dab"); + Q_CHECK_PTR(dab); + + Q_INT32 maskWidth = mask->width(); + Q_INT32 maskHeight = mask->height(); + + QRect dstRect; + + KisRectIteratorPixel it = dab->createRectIterator(0, 0, maskWidth, maskHeight, true); + KisColorSpace* cs = dab->colorSpace(); + while (!it.isDone()) { + cs->setAlpha(it.rawData(), Q_UINT8_MAX - mask->alphaAt(it.x(), it.y()), 1); + ++it; + } + + QRect dabRect = QRect(0, 0, maskWidth, maskHeight); + dstRect = QRect(destX, destY, dabRect.width(), dabRect.height()); + + KisImage * image = device->image(); + + if (image != 0) { + dstRect &= image->bounds(); + } + + if (dstRect.isNull() || dstRect.isEmpty() || !dstRect.isValid()) return; + + Q_INT32 sx = dstRect.x() - destX; + Q_INT32 sy = dstRect.y() - destY; + Q_INT32 sw = dstRect.width(); + Q_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/krita/plugins/paintops/defaultpaintops/kis_eraseop.h b/krita/plugins/paintops/defaultpaintops/kis_eraseop.h new file mode 100644 index 00000000..c15d11b3 --- /dev/null +++ b/krita/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 QString 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/krita/plugins/paintops/defaultpaintops/kis_penop.cc b/krita/plugins/paintops/defaultpaintops/kis_penop.cc new file mode 100644 index 00000000..d93a75d4 --- /dev/null +++ b/krita/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; + + Q_INT32 x = pt.roundX(); + Q_INT32 y = pt.roundY(); + + KisPaintDeviceSP dab = 0; + if (brush->brushType() == IMAGE || + brush->brushType() == PIPE_IMAGE) { + dab = brush->image(device->colorSpace(), info); + } + else { + // Compute mask without sub-pixel positioning + KisAlphaMaskSP mask = brush->mask(info); + dab = computeDab(mask); + } + + m_painter->setPressure(info.pressure); + QRect dabRect = QRect(0, 0, brush->maskWidth(info), brush->maskHeight(info)); + QRect dstRect = QRect(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()) { + Q_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; + } + + Q_INT32 sx = dstRect.x() - x; + Q_INT32 sy = dstRect.y() - y; + Q_INT32 sw = dstRect.width(); + Q_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/krita/plugins/paintops/defaultpaintops/kis_penop.h b/krita/plugins/paintops/defaultpaintops/kis_penop.h new file mode 100644 index 00000000..f548bed5 --- /dev/null +++ b/krita/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 QString 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/krita/plugins/paintops/defaultpaintops/kis_smudgeop.cc b/krita/plugins/paintops/defaultpaintops/kis_smudgeop.cc new file mode 100644 index 00000000..a339c062 --- /dev/null +++ b/krita/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(QWidget *parent, bool isTablet) + : super(parent) +{ + m_optionsWidget = new QWidget(parent, "brush option widget"); + QHBoxLayout * l = new QHBoxLayout(m_optionsWidget); + l->setAutoAdd(true); + m_rateLabel = new QLabel(i18n("Rate: "), m_optionsWidget); + m_rateSlider = new QSlider(0,100,1, 50, Qt::Horizontal, m_optionsWidget); + if(isTablet) + { + m_pressureVariation = new QLabel(i18n("Pressure variation: "), m_optionsWidget); + m_size = new QCheckBox(i18n("Size"), m_optionsWidget); + m_size->setChecked(true); + m_opacity = new QCheckBox(i18n("Opacity"), m_optionsWidget); + m_rate = new QCheckBox(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.")); + QToolButton* moreButton = new QToolButton(Qt::UpArrow, m_optionsWidget); + moreButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + moreButton->setMinimumSize(QSize(24,24)); // Bah, I had hoped the above line would make this unneeded + connect(moreButton, SIGNAL(clicked()), this, 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() == QDialog::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(QWidget * parent, const KisInputDevice& inputDevice) +{ + if (inputDevice == KisInputDevice::mouse()) { + // No options for mouse, only tablet devices + return new KisSmudgeOpSettings(parent, false); + } else { + return new KisSmudgeOpSettings(parent, 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 == mask + // retrieve mask + // else if brush == image + // retrieve image + // subsample (mask | image) for position -- pos should be double! + // apply filters to mask (colour | gradient | pattern | etc. + // composite filtered mask 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. + Q_INT32 x; + double xFraction; + Q_INT32 y; + double yFraction; + + splitCoordinate(pt.x(), &x, &xFraction); + splitCoordinate(pt.y(), &y, &yFraction); + + KisPaintDeviceSP dab = 0; + + Q_UINT8 origOpacity = m_painter->opacity(); + + if (m_pressureOpacity) { + if (!m_customOpacity) + m_painter->setOpacity((Q_INT8)(origOpacity * info.pressure)); + else + m_painter->setOpacity((Q_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 mask = brush->mask(adjustedInfo, xFraction, yFraction); + dab = computeDab(mask, KisMetaRegistry::instance()->csRegistry()->getAlpha8()); + } + + + m_painter->setPressure(adjustedInfo.pressure); + + QRect dabRect = QRect(0, 0, brush->maskWidth(adjustedInfo), + brush->maskHeight(adjustedInfo)); + QRect dstRect = QRect(x, y, dabRect.width(), dabRect.height()); + + KisImage * image = device->image(); + + if (image != 0) { + dstRect &= image->bounds(); + } + + Q_INT32 sw = dab->extent().width(); + Q_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((Q_UINT8)(double(opacity) * scaleToCurve(info.pressure, m_rateCurve)), OPACITY_TRANSPARENT, OPACITY_OPAQUE); + } else { + opacity = CLAMP((Q_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; + + Q_INT32 sx = dstRect.x() - x; + Q_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/krita/plugins/paintops/defaultpaintops/kis_smudgeop.h b/krita/plugins/paintops/defaultpaintops/kis_smudgeop.h new file mode 100644 index 00000000..26a82e07 --- /dev/null +++ b/krita/plugins/paintops/defaultpaintops/kis_smudgeop.h @@ -0,0 +1,117 @@ +/* + * 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 QWidget; +class QCheckBox; +class QLabel; +class QSlider; +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 QString pixmap() { return "paintbrush.png"; } + virtual KisPaintOpSettings *settings(QWidget * parent, const KisInputDevice& inputDevice); +}; + +class KisSmudgeOpSettings : public QObject, public KisPaintOpSettings { + Q_OBJECT + typedef KisPaintOpSettings super; +public: + KisSmudgeOpSettings(QWidget *parent, 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 QWidget *widget() const { return m_optionsWidget; } +private slots: + void slotCustomCurves(); +private: + void transferCurve(KCurve* curve, double* target); + QWidget *m_optionsWidget; + QLabel* m_rateLabel; + QSlider* m_rateSlider; + QLabel * m_pressureVariation; + QCheckBox * m_rate; + QCheckBox * m_size; + QCheckBox * 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/krita/plugins/paintops/defaultpaintops/kritadefaultpaintops.desktop b/krita/plugins/paintops/defaultpaintops/kritadefaultpaintops.desktop new file mode 100644 index 00000000..95982cd4 --- /dev/null +++ b/krita/plugins/paintops/defaultpaintops/kritadefaultpaintops.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=Krita/Paintop +Type=Service +X-KDE-Library=kritadefaultpaintops +X-Krita-Version=2 diff --git a/krita/plugins/paintops/defaultpaintops/paintbrush.png b/krita/plugins/paintops/defaultpaintops/paintbrush.png new file mode 100644 index 00000000..089567e3 Binary files /dev/null and b/krita/plugins/paintops/defaultpaintops/paintbrush.png differ diff --git a/krita/plugins/paintops/defaultpaintops/pencil.png b/krita/plugins/paintops/defaultpaintops/pencil.png new file mode 100644 index 00000000..5af23ad6 Binary files /dev/null and b/krita/plugins/paintops/defaultpaintops/pencil.png differ diff --git a/krita/plugins/paintops/defaultpaintops/src/README b/krita/plugins/paintops/defaultpaintops/src/README new file mode 100644 index 00000000..769ced65 --- /dev/null +++ b/krita/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/krita/plugins/paintops/defaultpaintops/src/pencil_01.svg b/krita/plugins/paintops/defaultpaintops/src/pencil_01.svg new file mode 100644 index 00000000..40319104 --- /dev/null +++ b/krita/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/krita/plugins/paintops/defaultpaintops/src/pencil_jonathan_dietrich_01.svg b/krita/plugins/paintops/defaultpaintops/src/pencil_jonathan_dietrich_01.svg new file mode 100644 index 00000000..4b29bb9a --- /dev/null +++ b/krita/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/krita/plugins/paintops/defaultpaintops/src/pennello_mauro_olivo_01.svg b/krita/plugins/paintops/defaultpaintops/src/pennello_mauro_olivo_01.svg new file mode 100644 index 00000000..b79fcd57 --- /dev/null +++ b/krita/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/krita/plugins/tools/Makefile.am b/krita/plugins/tools/Makefile.am new file mode 100644 index 00000000..eb40c4e9 --- /dev/null +++ b/krita/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/krita/plugins/tools/defaulttools/Makefile.am b/krita/plugins/tools/defaulttools/Makefile.am new file mode 100644 index 00000000..6f28508a --- /dev/null +++ b/krita/plugins/tools/defaulttools/Makefile.am @@ -0,0 +1,82 @@ +kde_services_DATA = kritadefaulttools.desktop + +# all_includes must remain last! +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kritadefaulttools_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 = kritadefaulttools.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 + + +kritadefaulttools_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritadefaulttools_la_LIBADD = ../../../libkritacommon.la $(LIB_KOPAINTER) $(LIB_KOFFICECORE) + +kritadefaulttools_la_METASOURCES = AUTO + +KDE_OPTIONS = nofinal + +kritapics_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 + + +kritapicsdir = $(kde_datadir)/krita/pics + diff --git a/krita/plugins/tools/defaulttools/closedhand_cursor.xpm b/krita/plugins/tools/defaulttools/closedhand_cursor.xpm new file mode 100644 index 00000000..b3d98f85 --- /dev/null +++ b/krita/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/krita/plugins/tools/defaulttools/default_tools.cc b/krita/plugins/tools/defaulttools/default_tools.cc new file mode 100644 index 00000000..c4edcfb3 --- /dev/null +++ b/krita/plugins/tools/defaulttools/default_tools.cc @@ -0,0 +1,88 @@ +/* + * default_tools.cc -- Part of Krita + * + * 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( kritadefaulttools, DefaultToolsFactory( "krita" ) ) + + +DefaultTools::DefaultTools(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(DefaultToolsFactory::instance()); + + if ( parent->inherits("KisToolRegistry") ) + { + KisToolRegistry * r = dynamic_cast(parent); + + 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/krita/plugins/tools/defaulttools/default_tools.h b/krita/plugins/tools/defaulttools/default_tools.h new file mode 100644 index 00000000..0088263d --- /dev/null +++ b/krita/plugins/tools/defaulttools/default_tools.h @@ -0,0 +1,43 @@ +/* + * 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 Krita'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 Krita. 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 +public: + DefaultTools(QObject *parent, const char *name, const QStringList &); + virtual ~DefaultTools(); + +}; + +#endif // DEFAULT_TOOLS_H_ diff --git a/krita/plugins/tools/defaulttools/kis_tool_brush.cc b/krita/plugins/tools/defaulttools/kis_tool_brush.cc new file mode 100644 index 00000000..a65795d1 --- /dev/null +++ b/krita/plugins/tools/defaulttools/kis_tool_brush.cc @@ -0,0 +1,167 @@ +/* + * kis_tool_brush.cc - part of Krita + * + * 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 QTimer(this); + Q_CHECK_PTR(m_timer); + + connect(m_timer, SIGNAL(timeout()), this, 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", Qt::Key_B, this, + 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(QEvent */*e*/) { + m_subject->canvasController()->kiscanvas()->update(); // remove the outline +} + + +void KisToolBrush::slotSetPaintingMode( int mode ) +{ + if (mode == QButton::On) { + // Direct painting + m_paintIncremental = true; + } + else { + m_paintIncremental = false; + } +} + + +QWidget* KisToolBrush::createOptionWidget(QWidget* parent) +{ + QWidget *widget = super::createOptionWidget(parent); + m_chkDirect = new QCheckBox(i18n("Paint direct"), widget, "chkDirect"); + m_chkDirect->setChecked(true); + connect(m_chkDirect, SIGNAL(stateChanged(int)), this, SLOT(slotSetPaintingMode(int))); + + m_optionLayout = new QGridLayout(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/krita/plugins/tools/defaulttools/kis_tool_brush.h b/krita/plugins/tools/defaulttools/kis_tool_brush.h new file mode 100644 index 00000000..0024213d --- /dev/null +++ b/krita/plugins/tools/defaulttools/kis_tool_brush.h @@ -0,0 +1,86 @@ +/* + * 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 QTimer; +class KisPoint; +class QHBoxLayout; +class QPainter; +class QRect; +class QCheckBox; +class QGridLayout; + +class KRITACORE_EXPORT KisToolBrush : public KisToolFreehand { + Q_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 Q_UINT32 priority() { return 0; } + QWidget* createOptionWidget(QWidget* parent); + +protected: + + virtual void initPaint(KisEvent *e); + virtual void endPaint(); + virtual void move(KisMoveEvent *e); + virtual void leave(QEvent *e); + +private slots: + + void timeoutPaint(); + void slotSetPaintingMode( int mode ); + +private: + + Q_INT32 m_rate; + QTimer * m_timer; + QGridLayout* m_optionLayout; + QCheckBox * 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/krita/plugins/tools/defaulttools/kis_tool_colorpicker.cc b/krita/plugins/tools/defaulttools/kis_tool_colorpicker.cc new file mode 100644 index 00000000..ae553952 --- /dev/null +++ b/krita/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() != QMouseEvent::LeftButton && e->button() != QMouseEvent::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; + } + } + + QPoint pos = QPoint(e->pos().floorX(), e->pos().floorY()); + + if (!img->bounds().contains(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(); + + Q_UINT8* data = new Q_UINT8[pixelSize]; + Q_UINT8** pixels = new Q_UINT8*[counts[m_radius]]; + Q_UINT8* weights = new Q_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 Q_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 Q_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() == QMouseEvent::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.toQColor(); + // 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.").arg(palette->filename()), i18n("Palette")); + } + } + } +} + +void KisToolColorPicker::displayPickedColor() +{ + if (m_pickedColor.data() && m_optionsWidget) { + + QValueVector channels = m_pickedColor.colorSpace()->channels(); + m_optionsWidget->listViewChannels->clear(); + + for (int i = channels.count() - 1; i >= 0 ; --i) { + QString channelValueText; + + if (m_normaliseValues) { + channelValueText = i18n("%1%").arg(m_pickedColor.colorSpace()->normalisedChannelValueText(m_pickedColor.data(), i)); + } else { + channelValueText = m_pickedColor.colorSpace()->channelValueText(m_pickedColor.data(), i); + } + + m_optionsWidget->listViewChannels->insertItem(new QListViewItem(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", Qt::Key_P, this, SLOT(activate()), collection, name()); + m_action->setToolTip(i18n("Color picker")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + +QWidget* KisToolColorPicker::createOptionWidget(QWidget* parent) +{ + m_optionsWidget = new ColorPickerOptionsWidget(parent); + + 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, SIGNAL(toggled(bool)), SLOT(slotSetUpdateColor(bool))); + connect(m_optionsWidget->cbNormaliseValues, SIGNAL(toggled(bool)), SLOT(slotSetNormaliseValues(bool))); + connect(m_optionsWidget->cbPalette, SIGNAL(toggled(bool)), + SLOT(slotSetAddPalette(bool))); + connect(m_optionsWidget->radius, SIGNAL(valueChanged(int)), + SLOT(slotChangeRadius(int))); + + KisResourceServerBase* srv = KisResourceServerRegistry::instance()->get("PaletteServer"); + + if (!srv) { + return m_optionsWidget; + } + + QValueList 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, SIGNAL(resourceAdded(KisResource*)), this, SLOT(slotAddPalette(KisResource*))); + + return m_optionsWidget; +} + +QWidget* 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/krita/plugins/tools/defaulttools/kis_tool_colorpicker.h b/krita/plugins/tools/defaulttools/kis_tool_colorpicker.h new file mode 100644 index 00000000..2834b8c6 --- /dev/null +++ b/krita/plugins/tools/defaulttools/kis_tool_colorpicker.h @@ -0,0 +1,87 @@ +/* + * 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 "qvaluevector.h" + +class ColorPickerOptionsWidget; +class KisResource; +class KisPalette; + +class KisToolColorPicker : public KisToolNonPaint { + + Q_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 QWidget* createOptionWidget(QWidget* parent); + virtual QWidget* optionWidget(); + virtual enumToolType toolType() { return TOOL_FILL; } + virtual Q_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; + QValueVector 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/krita/plugins/tools/defaulttools/kis_tool_duplicate.cc b/krita/plugins/tools/defaulttools/kis_tool_duplicate.cc new file mode 100644 index 00000000..71678e6f --- /dev/null +++ b/krita/plugins/tools/defaulttools/kis_tool_duplicate.cc @@ -0,0 +1,255 @@ +/* + * kis_tool_duplicate.cc - part of Krita + * + * 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(QPoint(-1,-1)) +{ + setName("tool_duplicate"); + m_subject = 0; + setCursor(KisCursor::load("tool_duplicate_cursor.png", 5, 5)); +} + +KisToolDuplicate::~KisToolDuplicate() +{ +} + +void KisToolDuplicate::activate() +{ + m_position = QPoint(-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 != QPoint(-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", Qt::Key_C, this, + 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 != QPoint(-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 == QPoint(-1,-1) ) + return; + + QPoint 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())); + QRect r = QRect(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.floorQPoint(); + } + + }else { + srcPos = painter()->duplicateOffset().floorQPoint(); + } + } else { + if(m_isOffsetNotUptodate) + srcPos = e->pos().floorQPoint() - m_position.floorQPoint(); + else + srcPos = m_offset.floorQPoint(); + } + + Q_INT32 x; + Q_INT32 y; + + // like KisPaintOp::splitCoordinate + x = (Q_INT32)((e->x() < 0) ? e->x() - 1 : e->x()); + y = (Q_INT32)((e->y() < 0) ? e->y() - 1 : e->y()); + srcPos = QPoint(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 != QPoint(-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); + } +} + +QString 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."); +} + +QWidget* KisToolDuplicate::createOptionWidget(QWidget* parent) +{ + QWidget* widget = KisToolPaint::createOptionWidget(parent); + m_healing = new QCheckBox(widget); + m_healing->setChecked( false); + addOptionWidgetOption(m_healing, new QLabel(i18n("Healing"), widget )); + m_healingRadius = new KIntNumInput(widget); + + KisBrush *brush = m_subject->currentBrush(); + int healingradius = 20; + if( brush ) + { + healingradius = 2 * QMAX(brush->width(),brush->height()); + } + + m_healingRadius->setValue( healingradius ); + addOptionWidgetOption(m_healingRadius, new QLabel(i18n("Healing radius"), widget )); + m_perspectiveCorrection = new QCheckBox(widget); + addOptionWidgetOption(m_perspectiveCorrection, new QLabel(i18n("Correct the perspective"), widget )); + return widget; +} + +#include "kis_tool_duplicate.moc" diff --git a/krita/plugins/tools/defaulttools/kis_tool_duplicate.h b/krita/plugins/tools/defaulttools/kis_tool_duplicate.h new file mode 100644 index 00000000..758542b8 --- /dev/null +++ b/krita/plugins/tools/defaulttools/kis_tool_duplicate.h @@ -0,0 +1,91 @@ +/* + * kis_tool_duplicate.h - part of Krita + * + * 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 QCheckBox; +class KIntNumInput; + +class KisToolDuplicate : public KisToolFreehand { + + typedef KisToolFreehand super; + Q_OBJECT + +public: + KisToolDuplicate(); + virtual ~KisToolDuplicate(); + + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_FREEHAND; } + virtual Q_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 QString quickHelp() const; + virtual QWidget* createOptionWidget(QWidget* parent); + +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; + QCheckBox* m_healing; + KIntNumInput* m_healingRadius; + QCheckBox* 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/krita/plugins/tools/defaulttools/kis_tool_ellipse.cc b/krita/plugins/tools/defaulttools/kis_tool_ellipse.cc new file mode 100644 index 00000000..dd8867c6 --- /dev/null +++ b/krita/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() == 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() & Qt::AltButton) { + KisPoint trans = event->pos() - m_dragEnd; + m_dragStart += trans; + m_dragEnd += trans; + } else { + KisPoint diag = event->pos() - (event->state() & Qt::ControlButton + ? m_dragCenter : m_dragStart); + // circle? + if (event->state() & Qt::ShiftButton) { + double size = QMAX(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() & Qt::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() == 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 (Qt::NotROP); + p.drawEllipse (QRect (controller->windowToView (start).floorQPoint(), controller->windowToView (end).floorQPoint())); + p.end (); +} + +void KisToolEllipse::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + KShortcut shortcut(Qt::Key_Plus); + shortcut.append(KShortcut(Qt::Key_F7)); + m_action = new KRadioAction(i18n("&Ellipse"), + "tool_ellipse", + shortcut, + this, + 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/krita/plugins/tools/defaulttools/kis_tool_ellipse.h b/krita/plugins/tools/defaulttools/kis_tool_ellipse.h new file mode 100644 index 00000000..a7bd595c --- /dev/null +++ b/krita/plugins/tools/defaulttools/kis_tool_ellipse.h @@ -0,0 +1,90 @@ +/* + * 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 + +public: + KisToolEllipse(); + virtual ~KisToolEllipse(); + + // + // KisCanvasObserver interface + // + + virtual void update (KisCanvasSubject *subject); + + // + // KisToolPaint interface + // + + virtual void setup(KActionCollection *collection); + virtual Q_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/krita/plugins/tools/defaulttools/kis_tool_fill.cc b/krita/plugins/tools/defaulttools/kis_tool_fill.cc new file mode 100644 index 00000000..3edd4f17 --- /dev/null +++ b/krita/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) { + QRect 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() != QMouseEvent::LeftButton) return; + if(!m_wasPressed) return; + m_wasPressed = false; + int x, y; + x = m_startPos.floorX(); + y = m_startPos.floorY(); + if (!m_currentImage->bounds().contains(x, y)) { + return; + } + flood(x, y); + notifyModified(); +} + +QWidget* KisToolFill::createOptionWidget(QWidget* parent) +{ + QWidget *widget = super::createOptionWidget(parent); + + m_lbThreshold = new QLabel(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, SIGNAL(valueChanged(int)), this, SLOT(slotSetThreshold(int))); + + m_checkUsePattern = new QCheckBox(i18n("Use pattern"), widget); + m_checkUsePattern->setChecked(m_usePattern); + connect(m_checkUsePattern, SIGNAL(toggled(bool)), this, SLOT(slotSetUsePattern(bool))); + + m_checkSampleMerged = new QCheckBox(i18n("Limit to current layer"), widget); + m_checkSampleMerged->setChecked(m_unmerged); + connect(m_checkSampleMerged, SIGNAL(toggled(bool)), this, SLOT(slotSetSampleMerged(bool))); + + m_checkFillSelection = new QCheckBox(i18n("Fill entire selection"), widget); + m_checkFillSelection->setChecked(m_fillOnlySelection); + connect(m_checkFillSelection, SIGNAL(toggled(bool)), this, 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", + Qt::Key_F, + this, + 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/krita/plugins/tools/defaulttools/kis_tool_fill.h b/krita/plugins/tools/defaulttools/kis_tool_fill.h new file mode 100644 index 00000000..2b121d9c --- /dev/null +++ b/krita/plugins/tools/defaulttools/kis_tool_fill.h @@ -0,0 +1,108 @@ +/* + * kis_tool_fill.h - part of Krayon^Krita + * + * 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 QWidget; +class QLabel; +class QCheckBox; +class KIntNumInput; +class KActionCollection; + +class KisToolFill : public KisToolPaint { + + typedef KisToolPaint super; + Q_OBJECT + +public: + + KisToolFill(); + virtual ~KisToolFill(); + + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_FILL; } + virtual Q_UINT32 priority() { return 0; } + + virtual void update(KisCanvasSubject *subject); + + virtual void buttonPress(KisButtonPressEvent*); + virtual void buttonRelease(KisButtonReleaseEvent*); + + bool flood(int startX, int startY); + + virtual QWidget* createOptionWidget(QWidget* parent); + +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; + Q_INT32 m_depth; + KisLayerSP m_lay; + Q_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; + + QLabel *m_lbThreshold; + KIntNumInput *m_slThreshold; + QCheckBox *m_checkUsePattern; + QCheckBox *m_checkSampleMerged; + QCheckBox *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/krita/plugins/tools/defaulttools/kis_tool_gradient.cc b/krita/plugins/tools/defaulttools/kis_tool_gradient.cc new file mode 100644 index 00000000..6c35de4e --- /dev/null +++ b/krita/plugins/tools/defaulttools/kis_tool_gradient.cc @@ -0,0 +1,309 @@ +/* + * kis_tool_gradient.cc - part of Krita + * + * 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_shape = 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 QRect&) +{ + if (m_dragging) + paintLine(gc); +} + +void KisToolGradient::buttonPress(KisButtonPressEvent *e) +{ + if (!m_subject || !m_subject->currentImg()) { + return; + } + + if (e->button() == QMouseEvent::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() & Qt::ShiftButton) == Qt::ShiftButton) { + m_endPos = straightLine(e->pos()); + } + else { + m_endPos = e->pos(); + } + + paintLine(); + } +} + +void KisToolGradient::buttonRelease(KisButtonReleaseEvent *e) +{ + if (m_dragging && e->button() == QMouseEvent::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() & Qt::ShiftButton) == Qt::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_shape, 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(); + QPen old = gc.pen(); + QPen pen(Qt::SolidLine); + + gc.setRasterOp(Qt::NotROP); + gc.setPen(pen); + gc.drawLine(start.floorQPoint(), end.floorQPoint()); + gc.setRasterOp(op); + gc.setPen(old); + } +} + +QWidget* KisToolGradient::createOptionWidget(QWidget* parent) +{ + QWidget *widget = super::createOptionWidget(parent); + Q_CHECK_PTR(widget); + + m_lbShape = new QLabel(i18n("Shape:"), widget); + m_lbRepeat = new QLabel(i18n("Repeat:"), widget); + + m_ckReverse = new QCheckBox(i18n("Reverse"), widget, "reverse_check"); + connect(m_ckReverse, SIGNAL(toggled(bool)), this, SLOT(slotSetReverse(bool))); + + m_cmbShape = new QComboBox(false, widget, "shape_combo"); + connect(m_cmbShape, SIGNAL(activated(int)), this, 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 QComboBox(false, widget, "repeat_combo"); + connect(m_cmbRepeat, SIGNAL(activated(int)), this, 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 QLabel(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, SIGNAL(valueChanged(double)), this, SLOT(slotSetAntiAliasThreshold(double))); + + addOptionWidgetOption(m_slAntiAliasThreshold, m_lbAntiAliasThreshold); + + return widget; +} + +void KisToolGradient::slotSetShape(int shape) +{ + m_shape = static_cast(shape); +} + +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", Qt::Key_G, this, + 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/krita/plugins/tools/defaulttools/kis_tool_gradient.h b/krita/plugins/tools/defaulttools/kis_tool_gradient.h new file mode 100644 index 00000000..c80529e3 --- /dev/null +++ b/krita/plugins/tools/defaulttools/kis_tool_gradient.h @@ -0,0 +1,123 @@ +/* + * 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 QLabel; +class QPoint; +class QWidget; +class QCheckBox; + + + +class KisToolGradient : public KisToolPaint { + + Q_OBJECT + typedef KisToolPaint super; + +public: + KisToolGradient(); + virtual ~KisToolGradient(); + + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_FILL; } + virtual Q_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 QRect& rc); + + QWidget* createOptionWidget(QWidget* parent); + +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_shape; + KisGradientPainter::enumGradientRepeat m_repeat; + + bool m_reverse; + double m_antiAliasThreshold; + + QLabel *m_lbShape; + QLabel *m_lbRepeat; + QCheckBox *m_ckReverse; + QComboBox *m_cmbShape; + QComboBox *m_cmbRepeat; + QLabel *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/krita/plugins/tools/defaulttools/kis_tool_line.cc b/krita/plugins/tools/defaulttools/kis_tool_line.cc new file mode 100644 index 00000000..cbdf5448 --- /dev/null +++ b/krita/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, QRect()); +} + +void KisToolLine::paint(KisCanvasPainter& gc, const QRect& 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() == QMouseEvent::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() & Qt::AltButton) { + KisPoint trans = e->pos() - m_endPos; + m_startPos += trans; + m_endPos += trans; + } else if (e->state() & Qt::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() == QMouseEvent::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() & Qt::ShiftButton) == Qt::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); + QRect rc; + + paintLine(gc, rc); + } +} + +void KisToolLine::paintLine(KisCanvasPainter& gc, const QRect&) +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + RasterOp op = gc.rasterOp(); + QPen old = gc.pen(); + QPen pen(Qt::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(Qt::NotROP); + gc.setPen(pen); + gc.drawLine(start.floorQPoint(), end.floorQPoint()); + 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", Qt::Key_L, this, + SLOT(activate()), collection, + name()); + m_action->setToolTip(i18n("Draw a line")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + +QString 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/krita/plugins/tools/defaulttools/kis_tool_line.h b/krita/plugins/tools/defaulttools/kis_tool_line.h new file mode 100644 index 00000000..8a84a819 --- /dev/null +++ b/krita/plugins/tools/defaulttools/kis_tool_line.h @@ -0,0 +1,99 @@ +/* + * 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 QPoint; +class QWidget; + + +class KisToolLine : public KisToolPaint { + + Q_OBJECT + typedef KisToolPaint super; + + public: + KisToolLine(); + virtual ~KisToolLine(); + + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_SHAPE; } + virtual Q_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 QRect& rc); + + virtual QString quickHelp() const; + + private: + void paintLine(); + void paintLine(KisCanvasPainter& gc, const QRect& 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/krita/plugins/tools/defaulttools/kis_tool_move.cc b/krita/plugins/tools/defaulttools/kis_tool_move.cc new file mode 100644 index 00000000..810bda37 --- /dev/null +++ b/krita/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 QTimer(this); + connect( m_repeatTimer, SIGNAL( timeout() ), this, 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() == QMouseEvent::LeftButton) { + QPoint pos = e->pos().floorQPoint(); + 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() == QMouseEvent::LeftButton) { + QPoint pos = e->pos().floorQPoint(); + if((e->state() & Qt::AltButton) || (e->state() & Qt::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() == QMouseEvent::LeftButton) { + m_strategy.endDrag(e->pos().floorQPoint()); + } +} + +void KisToolMove::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + m_action = new KRadioAction(i18n("&Move"), + "tool_move", + Qt::SHIFT+Qt::Key_V, + this, + SLOT(activate()), + collection, + name()); + m_action->setToolTip(i18n("Move")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + + +void KisToolMove::keyPress( QKeyEvent *e ) +{ + m_keyEvent = e; + + if (m_subject) { + + KisImageSP img = m_subject->currentImg(); + KisLayerSP dev; + + if (!img || !(dev = img->activeLayer())) + return; + + m_dragStart = QPoint( 0, 0 ); + m_strategy.startDrag( m_dragStart ); + m_steps = 1; + m_repeatTimer->start(200); + + } +} + +void KisToolMove::keyRelease(QKeyEvent *) +{ + m_repeatTimer->stop(); + + if ( m_subject && m_keyEvent) { + + if ( m_keyEvent->key() == Qt::Key_Left ) { + m_strategy.endDrag(QPoint( -m_steps, 0 )); + } + else if ( m_keyEvent->key() == Qt::Key_Right ) { + m_strategy.endDrag(QPoint(m_steps, 0) ); + } + else if ( m_keyEvent->key() == Qt::Key_Up ) { + m_strategy.endDrag(QPoint(0, -m_steps) ); + } + else if ( m_keyEvent->key() == Qt::Key_Down ) { + m_strategy.endDrag(QPoint(0, m_steps) ); + } + } + m_steps = 0; + m_keyEvent = 0; + +} + +void KisToolMove::slotMove() +{ + if (m_subject && m_keyEvent) { + + if ( m_keyEvent->key() == Qt::Key_Left ) { + m_strategy.drag(QPoint(-m_steps, 0) ); + } + else if ( m_keyEvent->key() == Qt::Key_Right ) { + m_strategy.drag(QPoint(m_steps, 0) ); + } + else if ( m_keyEvent->key() == Qt::Key_Up ) { + m_strategy.drag(QPoint(0, -m_steps) ); + } + else if ( m_keyEvent->key() == Qt::Key_Down ) { + m_strategy.drag(QPoint(0, m_steps) ); + } + + ++m_steps; + } + +} diff --git a/krita/plugins/tools/defaulttools/kis_tool_move.h b/krita/plugins/tools/defaulttools/kis_tool_move.h new file mode 100644 index 00000000..128a9661 --- /dev/null +++ b/krita/plugins/tools/defaulttools/kis_tool_move.h @@ -0,0 +1,88 @@ +/* + * 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 QTimer; + +class KisToolMove : public KisToolNonPaint { + + typedef KisToolNonPaint super; + Q_OBJECT + +public: + KisToolMove(); + virtual ~KisToolMove(); + +public: + virtual void update(KisCanvasSubject *subject); + +public: + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_TRANSFORM; } + virtual Q_UINT32 priority() { return 2; } + + virtual void buttonPress(KisButtonPressEvent *e); + virtual void move(KisMoveEvent *e); + virtual void buttonRelease(KisButtonReleaseEvent *e); + virtual void keyPress(QKeyEvent *e); + virtual void keyRelease(QKeyEvent *e); + +private slots: + + void slotMove(); + +private: + + KisCanvasSubject *m_subject; + KisStrategyMove m_strategy; + QPoint m_dragStart; + QTimer * m_repeatTimer; + QKeyEvent * 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/krita/plugins/tools/defaulttools/kis_tool_pan.cc b/krita/plugins/tools/defaulttools/kis_tool_pan.cc new file mode 100644 index 00000000..56da211d --- /dev/null +++ b/krita/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", Qt::SHIFT+Qt::Key_H, this, SLOT(activate()), collection, name()); + m_action->setToolTip(i18n("Pan")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + +#include "kis_tool_pan.moc" + diff --git a/krita/plugins/tools/defaulttools/kis_tool_pan.h b/krita/plugins/tools/defaulttools/kis_tool_pan.h new file mode 100644 index 00000000..d0f37669 --- /dev/null +++ b/krita/plugins/tools/defaulttools/kis_tool_pan.h @@ -0,0 +1,79 @@ +/* + * 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 + +public: + KisToolPan(); + virtual ~KisToolPan(); + + virtual void update(KisCanvasSubject *subject); + + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_VIEW; } + virtual Q_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; + Q_INT32 m_origScrollX; + Q_INT32 m_origScrollY; + bool m_dragging; + QCursor m_openHandCursor; + QCursor 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/krita/plugins/tools/defaulttools/kis_tool_rectangle.cc b/krita/plugins/tools/defaulttools/kis_tool_rectangle.cc new file mode 100644 index 00000000..13b81c7f --- /dev/null +++ b/krita/plugins/tools/defaulttools/kis_tool_rectangle.cc @@ -0,0 +1,187 @@ +/* + * kis_tool_rectangle.cc - part of Krita + * + * 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() == 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() & Qt::AltButton) { + KisPoint trans = event->pos() - m_dragEnd; + m_dragStart += trans; + m_dragEnd += trans; + } else { + KisPoint diag = event->pos() - (event->state() & Qt::ControlButton + ? m_dragCenter : m_dragStart); + // square? + if (event->state() & Qt::ShiftButton) { + double size = QMAX(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() & Qt::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() == 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 (Qt::NotROP); + p.drawRect (QRect (controller->windowToView (start).floorQPoint(), controller->windowToView (end).floorQPoint())); + 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", + Qt::Key_F6, + this, + 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/krita/plugins/tools/defaulttools/kis_tool_rectangle.h b/krita/plugins/tools/defaulttools/kis_tool_rectangle.h new file mode 100644 index 00000000..d9f1bf21 --- /dev/null +++ b/krita/plugins/tools/defaulttools/kis_tool_rectangle.h @@ -0,0 +1,95 @@ +/* + * kis_tool_rectangle.h - part of KImageShop^WKrayon^WKrita + * + * 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 QPainter; +class KisPainter; + +class KisToolRectangle : public KisToolShape { + + typedef KisToolShape super; + Q_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 Q_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; + QRect 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/krita/plugins/tools/defaulttools/kis_tool_text.cc b/krita/plugins/tools/defaulttools/kis_tool_text.cc new file mode 100644 index 00000000..b75f1b1b --- /dev/null +++ b/krita/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() == QMouseEvent::LeftButton) { + m_wasPressed = true; + } +} + +void KisToolText::buttonRelease(KisButtonReleaseEvent *e) +{ + if ( m_windowIsBeingShown ) return; + + if (m_subject && e->button() == QMouseEvent::LeftButton) { + if(!m_wasPressed) return; + m_wasPressed = false; + KisImageSP img = m_subject->currentImg(); + + m_windowIsBeingShown = true; + bool ok; + QString text = KInputDialog::getText(i18n("Font Tool"), i18n("Enter text:"), + QString::null, &ok); + if (!ok) { + m_windowIsBeingShown = false; + return; + } + + KisUndoAdapter *undoAdapter = img->undoAdapter(); + if (undoAdapter) { + undoAdapter->beginMacro(i18n("Text")); + } + + QFontMetrics metrics(m_font); + QRect boundingRect = 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()); + + QPixmap pixels(boundingRect.width(), boundingRect.height()); + { + QPainter paint(&pixels); + paint.fillRect(boundingRect, Qt::white); + paint.setFont(m_font); + paint.setBrush(QBrush(Qt::black)); + paint.drawText(xB, yB, text); + } + QImage image = pixels.convertToImage(); + + Q_INT32 height = boundingRect.height(); + Q_INT32 width = boundingRect.width(); + KisPaintLayer *layer = new KisPaintLayer(img, '"' + text + '"', OPACITY_OPAQUE); + KisGroupLayerSP parent = img->rootLayer(); + if (img->activeLayer()) + parent = img->activeLayer()->parent(); + img->addLayer(layer, parent, img->activeLayer()); + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + QRgb pixel = image.pixel(x, y); + // use the 'blackness' as alpha :) + Q_UINT8 alpha = 255 - qRed(pixel) * OPACITY_OPAQUE / 255; + QColor c = m_subject->fgColor().toQColor(); + layer->paintDevice()->setPixel(x, y, c, alpha); + } + } + + layer->setOpacity(m_opacity); + layer->setCompositeOp(m_compositeOp); + + layer->setVisible(false); + Q_INT32 x = QMAX(0, static_cast(e->x() - width/2)); + Q_INT32 y = QMAX(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/*, QWidget* parent! */ ); + m_lbFontName->setText(QString(m_font.family() + ", %1").arg(m_font.pointSize())); +} + +QWidget* KisToolText::createOptionWidget(QWidget* parent) +{ + QWidget *widget = super::createOptionWidget(parent); + + m_lbFont = new QLabel(i18n("Font: "), widget); + + QHBox *fontBox = new QHBox(widget); + m_lbFontName = new KSqueezedTextLabel(QString(m_font.family() + ", %1") + .arg(m_font.pointSize()), fontBox); + m_btnMoreFonts = new QPushButton("...", fontBox); + + connect(m_btnMoreFonts, SIGNAL(released()), this, 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", + Qt::SHIFT+Qt::Key_T, + this, + SLOT(activate()), + collection, + name()); + m_action->setExclusiveGroup("tools"); + m_action->setToolTip(i18n("Text")); + m_ownAction = true; + } +} + +#include "kis_tool_text.moc" diff --git a/krita/plugins/tools/defaulttools/kis_tool_text.h b/krita/plugins/tools/defaulttools/kis_tool_text.h new file mode 100644 index 00000000..b7bc857c --- /dev/null +++ b/krita/plugins/tools/defaulttools/kis_tool_text.h @@ -0,0 +1,80 @@ +/* + * 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 QFont; +class QLabel; +class QWidget; +class QPushButton; +class KSqueezedTextLabel; + + + +class KisToolText : public KisToolPaint { + typedef KisToolPaint super; + Q_OBJECT + +public: + KisToolText(); + virtual ~KisToolText(); + + virtual void update(KisCanvasSubject *subject); + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_FILL; } + virtual Q_UINT32 priority() { return 2; } + virtual void buttonPress(KisButtonPressEvent*); + virtual void buttonRelease(KisButtonReleaseEvent *e); + + virtual QWidget* createOptionWidget(QWidget* parent); +public slots: + virtual void setFont(); + +private: + KisCanvasSubject *m_subject; + QFont m_font; + QLabel *m_lbFont; + KSqueezedTextLabel *m_lbFontName; + QPushButton *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/krita/plugins/tools/defaulttools/kis_tool_zoom.cc b/krita/plugins/tools/defaulttools/kis_tool_zoom.cc new file mode 100644 index 00000000..a5567f83 --- /dev/null +++ b/krita/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 = QPoint(0, 0); + m_endPos = QPoint(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, SIGNAL(timeout()), 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, QRect()); +} + +void KisToolZoom::paint(KisCanvasPainter& gc, const QRect& 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().floorQPoint(); + m_endPos = e->pos().floorQPoint(); + m_dragging = true; + } + } +} + +void KisToolZoom::move(KisMoveEvent *e) +{ + if (m_subject && m_dragging) { + if (m_startPos != m_endPos) + paintOutline(); + + m_endPos = e->pos().floorQPoint(); + paintOutline(); + } +} + +void KisToolZoom::buttonRelease(KisButtonReleaseEvent *e) +{ + if (m_subject && m_dragging && e->button() == Qt::LeftButton) { + + KisCanvasController *controller = m_subject->canvasController(); + m_endPos = e->pos().floorQPoint(); + m_dragging = false; + + QPoint delta = m_endPos - m_startPos; + + if (sqrt(delta.x() * delta.x() + delta.y() * delta.y()) < 10) { + if (e->state() & Qt::ControlButton) { + controller->zoomOut(m_endPos.x(), m_endPos.y()); + } else { + controller->zoomIn(m_endPos.x(), m_endPos.y()); + } + } else { + controller->zoomTo(QRect(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() & (Qt::ShiftButton|Qt::ControlButton|Qt::AltButton); +#else + int state = kapp->keyboardModifiers() & (KApplication::ShiftModifier + |KApplication::ControlModifier|KApplication::Modifier1); +#endif + + if (state & Qt::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); + QRect rc; + + paintOutline(gc, rc); + } +} + +void KisToolZoom::paintOutline(KisCanvasPainter& gc, const QRect&) +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + RasterOp op = gc.rasterOp(); + QPen old = gc.pen(); + QPen pen(Qt::DotLine); + QPoint start; + QPoint end; + + Q_ASSERT(controller); + start = controller->windowToView(m_startPos); + end = controller->windowToView(m_endPos); + + gc.setRasterOp(Qt::NotROP); + gc.setPen(pen); + gc.drawRect(QRect(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", Qt::Key_Z, this, SLOT(activate()), collection, name()); + m_action->setToolTip(i18n("Zoom")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + +#include "kis_tool_zoom.moc" diff --git a/krita/plugins/tools/defaulttools/kis_tool_zoom.h b/krita/plugins/tools/defaulttools/kis_tool_zoom.h new file mode 100644 index 00000000..235c3a74 --- /dev/null +++ b/krita/plugins/tools/defaulttools/kis_tool_zoom.h @@ -0,0 +1,97 @@ +/* + * 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 + +public: + KisToolZoom(); + virtual ~KisToolZoom(); + +public: + virtual void update(KisCanvasSubject *subject); + +public: + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_VIEW; } + virtual Q_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 QRect& rc); + +private: + void paintOutline(); + void paintOutline(KisCanvasPainter& gc, const QRect& rc); + + +public slots: + + void activate(); + void deactivate(); + + +private slots: + void slotTimer(); + +private: + KisCanvasSubject *m_subject; + QPoint m_startPos; + QPoint m_endPos; + bool m_dragging; + QCursor m_plusCursor; + QCursor m_minusCursor; + QTimer 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/krita/plugins/tools/defaulttools/kritadefaulttools.desktop b/krita/plugins/tools/defaulttools/kritadefaulttools.desktop new file mode 100644 index 00000000..79c94c17 --- /dev/null +++ b/krita/plugins/tools/defaulttools/kritadefaulttools.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=Krita/Tool +Type=Service +X-KDE-Library=kritadefaulttools +X-Krita-Version=2 diff --git a/krita/plugins/tools/defaulttools/openhand_cursor.xpm b/krita/plugins/tools/defaulttools/openhand_cursor.xpm new file mode 100644 index 00000000..607879d5 --- /dev/null +++ b/krita/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/krita/plugins/tools/defaulttools/tool_color_fill.png b/krita/plugins/tools/defaulttools/tool_color_fill.png new file mode 100644 index 00000000..4f5b4ecf Binary files /dev/null and b/krita/plugins/tools/defaulttools/tool_color_fill.png differ diff --git a/krita/plugins/tools/defaulttools/tool_colorpicker.png b/krita/plugins/tools/defaulttools/tool_colorpicker.png new file mode 100644 index 00000000..d69b6e82 Binary files /dev/null and b/krita/plugins/tools/defaulttools/tool_colorpicker.png differ diff --git a/krita/plugins/tools/defaulttools/tool_duplicate.png b/krita/plugins/tools/defaulttools/tool_duplicate.png new file mode 100644 index 00000000..bf4ab7b0 Binary files /dev/null and b/krita/plugins/tools/defaulttools/tool_duplicate.png differ diff --git a/krita/plugins/tools/defaulttools/tool_duplicate_cursor.png b/krita/plugins/tools/defaulttools/tool_duplicate_cursor.png new file mode 100644 index 00000000..d71cdf60 Binary files /dev/null and b/krita/plugins/tools/defaulttools/tool_duplicate_cursor.png differ diff --git a/krita/plugins/tools/defaulttools/tool_ellipse.png b/krita/plugins/tools/defaulttools/tool_ellipse.png new file mode 100644 index 00000000..310932d4 Binary files /dev/null and b/krita/plugins/tools/defaulttools/tool_ellipse.png differ diff --git a/krita/plugins/tools/defaulttools/tool_ellipse_cursor.png b/krita/plugins/tools/defaulttools/tool_ellipse_cursor.png new file mode 100644 index 00000000..55e0c67e Binary files /dev/null and b/krita/plugins/tools/defaulttools/tool_ellipse_cursor.png differ diff --git a/krita/plugins/tools/defaulttools/tool_fill_cursor.png b/krita/plugins/tools/defaulttools/tool_fill_cursor.png new file mode 100644 index 00000000..7ad5888e Binary files /dev/null and b/krita/plugins/tools/defaulttools/tool_fill_cursor.png differ diff --git a/krita/plugins/tools/defaulttools/tool_freehand.png b/krita/plugins/tools/defaulttools/tool_freehand.png new file mode 100644 index 00000000..c5c90de0 Binary files /dev/null and b/krita/plugins/tools/defaulttools/tool_freehand.png differ diff --git a/krita/plugins/tools/defaulttools/tool_freehand_cursor.png b/krita/plugins/tools/defaulttools/tool_freehand_cursor.png new file mode 100644 index 00000000..a48b7e34 Binary files /dev/null and b/krita/plugins/tools/defaulttools/tool_freehand_cursor.png differ diff --git a/krita/plugins/tools/defaulttools/tool_gradient.png b/krita/plugins/tools/defaulttools/tool_gradient.png new file mode 100644 index 00000000..5ef05ad1 Binary files /dev/null and b/krita/plugins/tools/defaulttools/tool_gradient.png differ diff --git a/krita/plugins/tools/defaulttools/tool_gradient_cursor.png b/krita/plugins/tools/defaulttools/tool_gradient_cursor.png new file mode 100644 index 00000000..3cb25ae0 Binary files /dev/null and b/krita/plugins/tools/defaulttools/tool_gradient_cursor.png differ diff --git a/krita/plugins/tools/defaulttools/tool_line.png b/krita/plugins/tools/defaulttools/tool_line.png new file mode 100644 index 00000000..23c53e86 Binary files /dev/null and b/krita/plugins/tools/defaulttools/tool_line.png differ diff --git a/krita/plugins/tools/defaulttools/tool_line_cursor.png b/krita/plugins/tools/defaulttools/tool_line_cursor.png new file mode 100644 index 00000000..2f750ec4 Binary files /dev/null and b/krita/plugins/tools/defaulttools/tool_line_cursor.png differ diff --git a/krita/plugins/tools/defaulttools/tool_move.png b/krita/plugins/tools/defaulttools/tool_move.png new file mode 100644 index 00000000..e123f910 Binary files /dev/null and b/krita/plugins/tools/defaulttools/tool_move.png differ diff --git a/krita/plugins/tools/defaulttools/tool_pan.png b/krita/plugins/tools/defaulttools/tool_pan.png new file mode 100644 index 00000000..7ba6970e Binary files /dev/null and b/krita/plugins/tools/defaulttools/tool_pan.png differ diff --git a/krita/plugins/tools/defaulttools/tool_rectangle.png b/krita/plugins/tools/defaulttools/tool_rectangle.png new file mode 100644 index 00000000..7a7027fb Binary files /dev/null and b/krita/plugins/tools/defaulttools/tool_rectangle.png differ diff --git a/krita/plugins/tools/defaulttools/tool_rectangle_cursor.png b/krita/plugins/tools/defaulttools/tool_rectangle_cursor.png new file mode 100644 index 00000000..93a17d5a Binary files /dev/null and b/krita/plugins/tools/defaulttools/tool_rectangle_cursor.png differ diff --git a/krita/plugins/tools/defaulttools/tool_text.png b/krita/plugins/tools/defaulttools/tool_text.png new file mode 100644 index 00000000..7e208364 Binary files /dev/null and b/krita/plugins/tools/defaulttools/tool_text.png differ diff --git a/krita/plugins/tools/defaulttools/tool_text_cursor.png b/krita/plugins/tools/defaulttools/tool_text_cursor.png new file mode 100644 index 00000000..df52c660 Binary files /dev/null and b/krita/plugins/tools/defaulttools/tool_text_cursor.png differ diff --git a/krita/plugins/tools/defaulttools/tool_zoom.png b/krita/plugins/tools/defaulttools/tool_zoom.png new file mode 100644 index 00000000..73f326eb Binary files /dev/null and b/krita/plugins/tools/defaulttools/tool_zoom.png differ diff --git a/krita/plugins/tools/defaulttools/tool_zoom_minus_cursor.png b/krita/plugins/tools/defaulttools/tool_zoom_minus_cursor.png new file mode 100644 index 00000000..21b992c8 Binary files /dev/null and b/krita/plugins/tools/defaulttools/tool_zoom_minus_cursor.png differ diff --git a/krita/plugins/tools/defaulttools/tool_zoom_plus_cursor.png b/krita/plugins/tools/defaulttools/tool_zoom_plus_cursor.png new file mode 100644 index 00000000..072cea1c Binary files /dev/null and b/krita/plugins/tools/defaulttools/tool_zoom_plus_cursor.png differ diff --git a/krita/plugins/tools/defaulttools/wdgcolorpicker.ui b/krita/plugins/tools/defaulttools/wdgcolorpicker.ui new file mode 100644 index 00000000..4a26c53f --- /dev/null +++ b/krita/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 + + + + + layout2 + + + + unnamed + + + + cbPalette + + + Add to palette: + + + + + cmbPalette + + + + + + + cbNormaliseValues + + + Show colors as percentages + + + + + layout1 + + + + unnamed + + + + textLabel1 + + + Sample radius: + + + + + radius + + + 9 + + + 1 + + + + + + + + Channel + + + false + + + true + + + + + Value + + + false + + + true + + + + listViewChannels + + + true + + + NoSelection + + + + + + diff --git a/krita/plugins/tools/selectiontools/Makefile.am b/krita/plugins/tools/selectiontools/Makefile.am new file mode 100644 index 00000000..a3fc336f --- /dev/null +++ b/krita/plugins/tools/selectiontools/Makefile.am @@ -0,0 +1,55 @@ +kde_services_DATA = kritaselectiontools.desktop + +# all_includes must remain last! +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kritaselectiontools_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 = kritaselectiontools.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 + + +kritaselectiontools_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritaselectiontools_la_LIBADD = ../../../libkritacommon.la + +kritaselectiontools_la_METASOURCES = AUTO + +KDE_OPTIONS = nofinal + +kritapics_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 + +kritapicsdir = $(kde_datadir)/krita/pics + diff --git a/krita/plugins/tools/selectiontools/kis_tool_move_selection.cc b/krita/plugins/tools/selectiontools/kis_tool_move_selection.cc new file mode 100644 index 00000000..25ceb924 --- /dev/null +++ b/krita/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 QPoint& oldpos, const QPoint& newpos); + virtual ~KisSelectionOffsetCommand(); + + virtual void execute(); + virtual void unexecute(); + +private: + void moveTo(const QPoint& pos); + +private: + KisSelectionSP m_layer; + QPoint m_oldPos; + QPoint m_newPos; +}; + + KisSelectionOffsetCommand::KisSelectionOffsetCommand(KisSelectionSP layer, const QPoint& oldpos, const QPoint& 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 QPoint& pos) + { + if (m_layer->undoAdapter()) { + m_layer->undoAdapter()->setUndo(false); + } + + m_layer->setX(pos.x()); + m_layer->setY(pos.y()); + + m_layer->parentPaintDevice()->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() == QMouseEvent::LeftButton) { + QPoint pos = e->pos().floorQPoint(); + 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) { + QPoint pos = e->pos().floorQPoint(); + if((e->state() & Qt::AltButton) || (e->state() & Qt::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(); + + QRect 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 = QPoint(sel->getX(), sel->getY()); + m_dragStart = e->pos().floorQPoint(); + + lay->paintDevice()->setDirty(rc); + } + +} + +void KisToolMoveSelection::buttonRelease(KisButtonReleaseEvent *e) +{ + if (m_subject && e->button() == QMouseEvent::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", + Qt::SHIFT+Qt::Key_V, + this, + 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/krita/plugins/tools/selectiontools/kis_tool_move_selection.h b/krita/plugins/tools/selectiontools/kis_tool_move_selection.h new file mode 100644 index 00000000..b7eb47ec --- /dev/null +++ b/krita/plugins/tools/selectiontools/kis_tool_move_selection.h @@ -0,0 +1,74 @@ +/* + * 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 + +public: + KisToolMoveSelection(); + virtual ~KisToolMoveSelection(); + +public: + virtual void update(KisCanvasSubject *subject); + +public: + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_SELECT; } + virtual Q_UINT32 priority() { return 10; } + + virtual void buttonPress(KisButtonPressEvent *e); + virtual void move(KisMoveEvent *e); + virtual void buttonRelease(KisButtonReleaseEvent *e); + +private: + KisCanvasSubject *m_subject; + QPoint m_dragStart; + QPoint m_layerStart; + QPoint 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/krita/plugins/tools/selectiontools/kis_tool_select_brush.cc b/krita/plugins/tools/selectiontools/kis_tool_select_brush.cc new file mode 100644 index 00000000..9257d15a --- /dev/null +++ b/krita/plugins/tools/selectiontools/kis_tool_select_brush.cc @@ -0,0 +1,168 @@ +/* + * kis_tool_select_brush.cc - part of Krita + * + * 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(Qt::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 mask 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, + SLOT(activate()), collection, + name()); + Q_CHECK_PTR(m_action); + m_action->setToolTip(i18n("Paint a selection")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + +QWidget* KisToolSelectBrush::createOptionWidget(QWidget* parent) +{ + Q_UNUSED(parent); + // Commented out due to the fact that this doesn't actually work if you change the action +#if 0 + m_optWidget = new KisSelectionOptions(parent, m_subject); + Q_CHECK_PTR(m_optWidget); + m_optWidget->setCaption(i18n("Selection Brush")); + + QVBoxLayout * l = dynamic_cast(m_optWidget->layout()); + l->addItem(new QSpacerItem(1, 1, QSizePolicy::Fixed, QSizePolicy::Expanding)); + + return m_optWidget; +#endif + return 0; +} + +QWidget* KisToolSelectBrush::optionWidget() +{ + return m_optWidget; +} + +#include "kis_tool_select_brush.moc" diff --git a/krita/plugins/tools/selectiontools/kis_tool_select_brush.h b/krita/plugins/tools/selectiontools/kis_tool_select_brush.h new file mode 100644 index 00000000..cc49cd5e --- /dev/null +++ b/krita/plugins/tools/selectiontools/kis_tool_select_brush.h @@ -0,0 +1,82 @@ +/* + * kis_tool_select_brush.h - part of Krita + * + * 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 QWidget; +class KisPoint; +class KisSelectedTransaction; +class KisSelectionOptions; + +/** + * The selection brush creates a selection by painting with the current + * brush shape. 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 + typedef KisToolFreehand super; + +public: + KisToolSelectBrush(); + virtual ~KisToolSelectBrush(); + + virtual void setup(KActionCollection *collection); + virtual Q_UINT32 priority() { return 1; } + virtual enumToolType toolType() { return TOOL_SELECT; } + virtual QWidget* createOptionWidget(QWidget* parent); + virtual QWidget* 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/krita/plugins/tools/selectiontools/kis_tool_select_contiguous.cc b/krita/plugins/tools/selectiontools/kis_tool_select_contiguous.cc new file mode 100644 index 00000000..01acbbcb --- /dev/null +++ b/krita/plugins/tools/selectiontools/kis_tool_select_contiguous.cc @@ -0,0 +1,234 @@ +/* + * kis_tool_select_contiguous - part of Krayon^WKrita + * + * 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; + QPoint pos; + + if (e->button() != QMouseEvent::LeftButton && e->button() != QMouseEvent::RightButton) + return; + + if (!(img = m_subject->currentImg())) + return; + + dev = img->activeDevice(); + + if (!dev || !img->activeLayer()->visible()) + return; + + QApplication::setOverrideCursor(KisCursor::waitCursor()); + + pos = QPoint(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); + + QApplication::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, + 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()); +// }; +} + + +QWidget* KisToolSelectContiguous::createOptionWidget(QWidget* parent) +{ + m_optWidget = new KisSelectionOptions(parent, m_subject); + Q_CHECK_PTR(m_optWidget); + m_optWidget->setCaption(i18n("Contiguous Area Selection")); + + QVBoxLayout * l = dynamic_cast(m_optWidget->layout()); + l->setSpacing( 6 ); + + connect (m_optWidget, SIGNAL(actionChanged(int)), this, SLOT(slotSetAction(int))); + + QHBoxLayout * hbox = new QHBoxLayout(l); + Q_CHECK_PTR(hbox); + + QLabel * lbl = new QLabel(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, SIGNAL(valueChanged(int)), this, SLOT(slotSetFuzziness(int))); + + QCheckBox* samplemerged = new QCheckBox(i18n("Sample merged"), m_optWidget); + l->addWidget( samplemerged ); + samplemerged->setChecked(m_sampleMerged); + connect(samplemerged, SIGNAL(stateChanged(int)), + this, SLOT(slotSetSampleMerged(int))); + + l->addItem(new QSpacerItem(1, 1, QSizePolicy::Fixed, QSizePolicy::Expanding)); + + return m_optWidget; +} + +QWidget* KisToolSelectContiguous::optionWidget() +{ + return m_optWidget; +} + +void KisToolSelectContiguous::slotSetSampleMerged(int state) +{ + if (state == QButton::NoChange) + return; + m_sampleMerged = (state == QButton::On); +} + +#include "kis_tool_select_contiguous.moc" diff --git a/krita/plugins/tools/selectiontools/kis_tool_select_contiguous.h b/krita/plugins/tools/selectiontools/kis_tool_select_contiguous.h new file mode 100644 index 00000000..cc91b3ef --- /dev/null +++ b/krita/plugins/tools/selectiontools/kis_tool_select_contiguous.h @@ -0,0 +1,94 @@ +/* + * kis_tool_select_contiguous.h - part of KImageShop^WKrayon^Krita + * + * 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 QWidget; +class QVBoxLayout; +class QCheckBox; +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 + +public: + KisToolSelectContiguous(); + virtual ~KisToolSelectContiguous(); + +public: + virtual void update(KisCanvasSubject *subject); + + virtual void setup(KActionCollection *collection); + virtual Q_UINT32 priority() { return 7; } + virtual enumToolType toolType() { return TOOL_SELECT; }; + + virtual QWidget* createOptionWidget(QWidget* parent); + virtual QWidget* 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/krita/plugins/tools/selectiontools/kis_tool_select_elliptical.cc b/krita/plugins/tools/selectiontools/kis_tool_select_elliptical.cc new file mode 100644 index 00000000..226277b2 --- /dev/null +++ b/krita/plugins/tools/selectiontools/kis_tool_select_elliptical.cc @@ -0,0 +1,321 @@ +/* + * kis_tool_select_elliptical.cc -- part of Krita + * + * 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, QRect()); +} + +void KisToolSelectElliptical::paint(KisCanvasPainter& gc, const QRect& 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() == 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() & Qt::AltButton) { + KisPoint trans = e->pos() - m_endPos; + m_startPos += trans; + m_endPos += trans; + } else { + KisPoint diag = e->pos() - (e->state() & Qt::ControlButton + ? m_centerPos : m_startPos); + // circle? + if (e->state() & Qt::ShiftButton) { + double size = QMAX(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() & Qt::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() == LeftButton) { + + paintOutline(); + + if (m_startPos == m_endPos) { + clearSelection(); + } else { + QApplication::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(); + } + QRect rc( m_startPos.floorQPoint(), m_endPos.floorQPoint()); + rc = rc.normalize(); + + KisSelectionSP tmpSel = new KisSelection(dev); + KisAutobrushCircleShape shape(rc.width(),rc.height(), 1, 1); + Q_UINT8 value; + for (int y = 0; y <= rc.height(); y++) + for (int x = 0; x <= rc.width(); x++) + { + value = MAX_SELECTED - shape.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); + + QApplication::restoreOverrideCursor(); + } + } + m_selecting = false; + } +} + +void KisToolSelectElliptical::paintOutline() +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + KisCanvas *canvas = controller->kiscanvas(); + KisCanvasPainter gc(canvas); + QRect rc; + + paintOutline(gc, rc); + } +} + +void KisToolSelectElliptical::paintOutline(KisCanvasPainter& gc, const QRect&) +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + RasterOp op = gc.rasterOp(); + QPen old = gc.pen(); + QPen pen(Qt::DotLine); + QPoint start; + QPoint end; + + Q_ASSERT(controller); + start = controller->windowToView(m_startPos).floorQPoint(); + end = controller->windowToView(m_endPos).floorQPoint(); + + gc.setRasterOp(Qt::NotROP); + gc.setPen(pen); + gc.drawEllipse(QRect(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" , + Qt::Key_J, + this, + SLOT(activate()), + collection, + name()); + Q_CHECK_PTR(m_action); + m_action->setToolTip(i18n("Select an elliptical area")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + +QWidget* KisToolSelectElliptical::createOptionWidget(QWidget* parent) +{ + m_optWidget = new KisSelectionOptions(parent, m_subject); + Q_CHECK_PTR(m_optWidget); + m_optWidget->setCaption(i18n("Elliptical Selection")); + + connect (m_optWidget, SIGNAL(actionChanged(int)), this, SLOT(slotSetAction(int))); + + QVBoxLayout * l = dynamic_cast(m_optWidget->layout()); + l->addItem(new QSpacerItem(1, 1, QSizePolicy::Fixed, QSizePolicy::Expanding)); + + return m_optWidget; +} + +QWidget* KisToolSelectElliptical::optionWidget() +{ + return m_optWidget; +} + + + +#include "kis_tool_select_elliptical.moc" diff --git a/krita/plugins/tools/selectiontools/kis_tool_select_elliptical.h b/krita/plugins/tools/selectiontools/kis_tool_select_elliptical.h new file mode 100644 index 00000000..e3b46737 --- /dev/null +++ b/krita/plugins/tools/selectiontools/kis_tool_select_elliptical.h @@ -0,0 +1,98 @@ +/* + * kis_tool_select_elliptical.h - part of Krayon^WKrita + * + * 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 + +public: + KisToolSelectElliptical(); + virtual ~KisToolSelectElliptical(); + + virtual void update(KisCanvasSubject *subject); + + virtual void setup(KActionCollection *collection); + virtual Q_UINT32 priority() { return 4; } + virtual QWidget * createOptionWidget(QWidget* parent); + virtual QWidget* optionWidget(); + virtual enumToolType toolType() { return TOOL_SELECT; } + + virtual void paint(KisCanvasPainter& gc); + virtual void paint(KisCanvasPainter& gc, const QRect& 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 QRect& 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/krita/plugins/tools/selectiontools/kis_tool_select_eraser.cc b/krita/plugins/tools/selectiontools/kis_tool_select_eraser.cc new file mode 100644 index 00000000..6880c61b --- /dev/null +++ b/krita/plugins/tools/selectiontools/kis_tool_select_eraser.cc @@ -0,0 +1,156 @@ +/* + * kis_tool_select_brush.cc - part of Krita + * + * 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(Qt::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 mask 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, + 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; + } +} + +QWidget* KisToolSelectEraser::createOptionWidget(QWidget* parent) +{ + Q_UNUSED(parent); + // Commented out due to the fact that this doesn't actually work if you change the action +#if 0 + m_optWidget = new KisSelectionOptions(parent, m_subject); + Q_CHECK_PTR(m_optWidget); + m_optWidget->setCaption(i18n("Selection Eraser")); + + QVBoxLayout * l = dynamic_cast(m_optWidget->layout()); + l->addItem(new QSpacerItem(1, 1, QSizePolicy::Fixed, QSizePolicy::Expanding)); + + return m_optWidget; +#endif + return 0; +} + +QWidget* KisToolSelectEraser::optionWidget() +{ + return m_optWidget; +} + +#include "kis_tool_select_eraser.moc" + diff --git a/krita/plugins/tools/selectiontools/kis_tool_select_eraser.h b/krita/plugins/tools/selectiontools/kis_tool_select_eraser.h new file mode 100644 index 00000000..092122c8 --- /dev/null +++ b/krita/plugins/tools/selectiontools/kis_tool_select_eraser.h @@ -0,0 +1,81 @@ +/* + * kis_tool_select_eraser.h - part of Krita + * + * 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 shape. 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 + typedef KisToolFreehand super; + +public: + KisToolSelectEraser(); + virtual ~KisToolSelectEraser(); + + virtual void setup(KActionCollection *collection); + virtual Q_UINT32 priority() { return 2; } + virtual enumToolType toolType() { return TOOL_SELECT; } + virtual QWidget* createOptionWidget(QWidget* parent); + virtual QWidget* 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/krita/plugins/tools/selectiontools/kis_tool_select_outline.cc b/krita/plugins/tools/selectiontools/kis_tool_select_outline.cc new file mode 100644 index 00000000..fe76c989 --- /dev/null +++ b/krita/plugins/tools/selectiontools/kis_tool_select_outline.cc @@ -0,0 +1,295 @@ +/* + * kis_tool_select_freehand.h - part of Krayon^WKrita + * + * 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() == 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() == LeftButton) { + m_dragging = false; + deactivate(); + + KisImageSP img = m_subject->currentImg(); + + if (img && img->activeDevice()) { + QApplication::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(Qt::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) { + QRect dirty(painter.dirtyRect()); + dev->setDirty(dirty); + dev->emitSelectionChanged(dirty); + } else { + dev->setDirty(); + dev->emitSelectionChanged(); + } + + if (img->undo()) + img->undoAdapter()->addCommand(t); + + QApplication::restoreOverrideCursor(); + } + + m_points.clear(); + } +} + +void KisToolSelectOutline::paint(KisCanvasPainter& gc) +{ + draw(gc); +} + +void KisToolSelectOutline::paint(KisCanvasPainter& gc, const QRect&) +{ + 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()) { + QPen pen(Qt::white, 0, Qt::DotLine); + + gc.setPen(pen); + gc.setRasterOp(Qt::XorROP); + + KisCanvasController *controller = m_subject->canvasController(); + KisPoint start, end; + QPoint startPos; + QPoint endPos; + + startPos = controller->windowToView(m_dragStart.floorQPoint()); + endPos = controller->windowToView(m_dragEnd.floorQPoint()); + gc.drawLine(startPos, endPos); + } +} + +void KisToolSelectOutline::deactivate() +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + KisCanvas *canvas = controller->kiscanvas(); + KisCanvasPainter gc(canvas); + + QPen pen(Qt::white, 0, Qt::DotLine); + + gc.setPen(pen); + gc.setRasterOp(Qt::XorROP); + + KisPoint start, end; + QPoint startPos; + QPoint 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.floorQPoint()); + endPos = controller->windowToView(end.floorQPoint()); + + 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, + SLOT(activate()), + collection, + name()); + Q_CHECK_PTR(m_action); + m_action->setExclusiveGroup("tools"); + m_action->setToolTip(i18n("Select an outline")); + m_ownAction = true; + } +} + + +QWidget* KisToolSelectOutline::createOptionWidget(QWidget* parent) +{ + m_optWidget = new KisSelectionOptions(parent, m_subject); + Q_CHECK_PTR(m_optWidget); + m_optWidget->setCaption(i18n("Outline Selection")); + + connect (m_optWidget, SIGNAL(actionChanged(int)), this, SLOT(slotSetAction(int))); + + QVBoxLayout * l = dynamic_cast(m_optWidget->layout()); + l->addItem(new QSpacerItem(1, 1, QSizePolicy::Fixed, QSizePolicy::Expanding)); + + return m_optWidget; +} + +QWidget* 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/krita/plugins/tools/selectiontools/kis_tool_select_outline.h b/krita/plugins/tools/selectiontools/kis_tool_select_outline.h new file mode 100644 index 00000000..eda10504 --- /dev/null +++ b/krita/plugins/tools/selectiontools/kis_tool_select_outline.h @@ -0,0 +1,100 @@ +/* + * kis_tool_select_freehand.h - part of Krayon^WKrita + * + * 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 +public: + KisToolSelectOutline(); + virtual ~KisToolSelectOutline(); + + virtual void update (KisCanvasSubject *subject); + + virtual void setup(KActionCollection *collection); + virtual Q_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); + + QWidget* createOptionWidget(QWidget* parent); + virtual QWidget* optionWidget(); + +public slots: + virtual void slotSetAction(int); + virtual void activate(); + void deactivate(); + +protected: + virtual void paint(KisCanvasPainter& gc); + virtual void paint(KisCanvasPainter& gc, const QRect& rc); + void draw(KisCanvasPainter& gc); + void draw(); + + +protected: + KisPoint m_dragStart; + KisPoint m_dragEnd; + + bool m_dragging; +private: + typedef QValueVector 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/krita/plugins/tools/selectiontools/kis_tool_select_polygonal.cc b/krita/plugins/tools/selectiontools/kis_tool_select_polygonal.cc new file mode 100644 index 00000000..dc7cec97 --- /dev/null +++ b/krita/plugins/tools/selectiontools/kis_tool_select_polygonal.cc @@ -0,0 +1,315 @@ +/* + * kis_tool_select_polygonal.h - part of Krayon^WKrita + * + * 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() == 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() == 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()) { + QApplication::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(Qt::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) { + QRect rect(painter.dirtyRect()); + dev->setDirty(rect); + dev->emitSelectionChanged(rect); + } else { + dev->setDirty(); + dev->emitSelectionChanged(); + } + + if (img->undo()) img->undoAdapter()->addCommand(t); + + QApplication::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() == LeftButton) { + m_dragging = false; + m_points.append (m_dragEnd); + } + + if (m_dragging && event->button() == RightButton) { + + } +} + +void KisToolSelectPolygonal::paint(KisCanvasPainter& gc) +{ + draw(gc); +} + +void KisToolSelectPolygonal::paint(KisCanvasPainter& gc, const QRect&) +{ + 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; + + QPen pen(Qt::white, 0, Qt::DotLine); + + gc.setPen(pen); + gc.setRasterOp(Qt::XorROP); + + KisCanvasController *controller = m_subject->canvasController(); + KisPoint start, end; + QPoint startPos; + QPoint endPos; + + if (m_dragging) { + startPos = controller->windowToView(m_dragStart.floorQPoint()); + endPos = controller->windowToView(m_dragEnd.floorQPoint()); + 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.floorQPoint()); + endPos = controller->windowToView(end.floorQPoint()); + + 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, + SLOT(activate()), + collection, + name()); + Q_CHECK_PTR(m_action); + m_action->setExclusiveGroup("tools"); + m_action->setToolTip(i18n("Select a polygonal area")); + m_ownAction = true; + } +} + + +QWidget* KisToolSelectPolygonal::createOptionWidget(QWidget* parent) +{ + m_optWidget = new KisSelectionOptions(parent, m_subject); + Q_CHECK_PTR(m_optWidget); + m_optWidget->setCaption(i18n("Polygonal Selection")); + + connect (m_optWidget, SIGNAL(actionChanged(int)), this, SLOT(slotSetAction(int))); + + QVBoxLayout * l = dynamic_cast(m_optWidget->layout()); + l->addItem(new QSpacerItem(1, 1, QSizePolicy::Fixed, QSizePolicy::Expanding)); + + return m_optWidget; +} + +QWidget* 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/krita/plugins/tools/selectiontools/kis_tool_select_polygonal.h b/krita/plugins/tools/selectiontools/kis_tool_select_polygonal.h new file mode 100644 index 00000000..05764c61 --- /dev/null +++ b/krita/plugins/tools/selectiontools/kis_tool_select_polygonal.h @@ -0,0 +1,105 @@ +/* + * kis_tool_select_polygonal.h - part of Krayon^WKrita + * + * 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 +public: + KisToolSelectPolygonal(); + virtual ~KisToolSelectPolygonal(); + + // + // KisCanvasObserver interface + // + + virtual void update (KisCanvasSubject *subject); + + // + // KisToolPaint interface + // + + virtual void setup(KActionCollection *collection); + virtual Q_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(); + QWidget* createOptionWidget(QWidget* parent); + virtual QWidget* optionWidget(); + +public slots: + virtual void slotSetAction(int); + virtual void activate(); + void deactivate(); + +protected: + virtual void paint(KisCanvasPainter& gc); + virtual void paint(KisCanvasPainter& gc, const QRect& rc); + void draw(KisCanvasPainter& gc); + void draw(); + +protected: + KisPoint m_dragStart; + KisPoint m_dragEnd; + + bool m_dragging; +private: + typedef QValueVector 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/krita/plugins/tools/selectiontools/kis_tool_select_rectangular.cc b/krita/plugins/tools/selectiontools/kis_tool_select_rectangular.cc new file mode 100644 index 00000000..61a4c292 --- /dev/null +++ b/krita/plugins/tools/selectiontools/kis_tool_select_rectangular.cc @@ -0,0 +1,323 @@ + +/* + * kis_tool_select_rectangular.cc -- part of Krita + * + * 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, QRect()); +} + +void KisToolSelectRectangular::paint(KisCanvasPainter& gc, const QRect& 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() == 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() & Qt::AltButton) { + KisPoint trans = e->pos() - m_endPos; + m_startPos += trans; + m_endPos += trans; + } else { + KisPoint diag = e->pos() - (e->state() & Qt::ControlButton + ? m_centerPos : m_startPos); + // square? + if (e->state() & Qt::ShiftButton) { + double size = QMAX(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() & Qt::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() == 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()) { + + QApplication::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(); + QRect rc(m_startPos.floorQPoint(), m_endPos.floorQPoint()); + rc = rc.normalize(); + + // We don't want the border of the 'rectangle' to be included in our selection + rc.setSize(rc.size() - QSize(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(); + + QApplication::restoreOverrideCursor(); + } + } + + m_selecting = false; + } +} + +void KisToolSelectRectangular::paintOutline() +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + KisCanvas *canvas = controller->kiscanvas(); + KisCanvasPainter gc(canvas); + QRect rc; + + paintOutline(gc, rc); + } +} + +void KisToolSelectRectangular::paintOutline(KisCanvasPainter& gc, const QRect&) +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + RasterOp op = gc.rasterOp(); + QPen old = gc.pen(); + QPen pen(Qt::DotLine); + QPoint start; + QPoint end; + + Q_ASSERT(controller); + start = controller->windowToView(m_startPos.floorQPoint()); + end = controller->windowToView(m_endPos.floorQPoint()); + + gc.setRasterOp(Qt::NotROP); + gc.setPen(pen); + gc.drawRect(QRect(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", + Qt::Key_R, + this, + SLOT(activate()), + collection, + name()); + Q_CHECK_PTR(m_action); + m_action->setExclusiveGroup("tools"); + m_action->setToolTip(i18n("Select a rectangular area")); + m_ownAction = true; + } +} + +QWidget* KisToolSelectRectangular::createOptionWidget(QWidget* parent) +{ + m_optWidget = new KisSelectionOptions(parent, m_subject); + Q_CHECK_PTR(m_optWidget); + m_optWidget->setCaption(i18n("Rectangular Selection")); + + connect (m_optWidget, SIGNAL(actionChanged(int)), this, SLOT(slotSetAction(int))); + + QVBoxLayout * l = dynamic_cast(m_optWidget->layout()); + l->addItem(new QSpacerItem(1, 1, QSizePolicy::Fixed, QSizePolicy::Expanding)); + + return m_optWidget; +} + +QWidget* KisToolSelectRectangular::optionWidget() +{ + return m_optWidget; +} + + + + +#include "kis_tool_select_rectangular.moc" diff --git a/krita/plugins/tools/selectiontools/kis_tool_select_rectangular.h b/krita/plugins/tools/selectiontools/kis_tool_select_rectangular.h new file mode 100644 index 00000000..2724a2ca --- /dev/null +++ b/krita/plugins/tools/selectiontools/kis_tool_select_rectangular.h @@ -0,0 +1,94 @@ +/* + * kis_tool_select_rectangular.h - part of Krita + * + * 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 + +public: + KisToolSelectRectangular(); + virtual ~KisToolSelectRectangular(); + + virtual void update(KisCanvasSubject *subject); + + virtual void setup(KActionCollection *collection); + virtual Q_UINT32 priority() { return 3; } + virtual enumToolType toolType() { return TOOL_SELECT; } + virtual QWidget * createOptionWidget(QWidget* parent); + virtual QWidget* optionWidget(); + + virtual void paint(KisCanvasPainter& gc); + virtual void paint(KisCanvasPainter& gc, const QRect& 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 QRect& 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/krita/plugins/tools/selectiontools/kritaselectiontools.desktop b/krita/plugins/tools/selectiontools/kritaselectiontools.desktop new file mode 100644 index 00000000..0cd006ba --- /dev/null +++ b/krita/plugins/tools/selectiontools/kritaselectiontools.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=Krita/Tool +Type=Service +X-KDE-Library=kritaselectiontools +X-Krita-Version=2 diff --git a/krita/plugins/tools/selectiontools/selection_tools.cc b/krita/plugins/tools/selectiontools/selection_tools.cc new file mode 100644 index 00000000..1297aa31 --- /dev/null +++ b/krita/plugins/tools/selectiontools/selection_tools.cc @@ -0,0 +1,77 @@ +/* + * selection_tools.cc -- Part of Krita + * + * 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( kritaselectiontools, SelectionToolsFactory( "krita" ) ) + + +SelectionTools::SelectionTools(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(SelectionToolsFactory::instance()); + + if ( parent->inherits("KisToolRegistry") ) + { + KisToolRegistry * r = dynamic_cast(parent); + 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/krita/plugins/tools/selectiontools/selection_tools.h b/krita/plugins/tools/selectiontools/selection_tools.h new file mode 100644 index 00000000..ad023762 --- /dev/null +++ b/krita/plugins/tools/selectiontools/selection_tools.h @@ -0,0 +1,43 @@ +/* + * 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 Krita'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 Krita. 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 +public: + SelectionTools(QObject *parent, const char *name, const QStringList &); + virtual ~SelectionTools(); + +}; + +#endif // SELECTION_TOOLS_H_ diff --git a/krita/plugins/tools/selectiontools/tool_brush_selection.png b/krita/plugins/tools/selectiontools/tool_brush_selection.png new file mode 100644 index 00000000..7f5ce541 Binary files /dev/null and b/krita/plugins/tools/selectiontools/tool_brush_selection.png differ diff --git a/krita/plugins/tools/selectiontools/tool_brush_selection.svg b/krita/plugins/tools/selectiontools/tool_brush_selection.svg new file mode 100644 index 00000000..e98207f7 --- /dev/null +++ b/krita/plugins/tools/selectiontools/tool_brush_selection.svg @@ -0,0 +1,827 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/krita/plugins/tools/selectiontools/tool_brush_selection_cursor.png b/krita/plugins/tools/selectiontools/tool_brush_selection_cursor.png new file mode 100644 index 00000000..238c839e Binary files /dev/null and b/krita/plugins/tools/selectiontools/tool_brush_selection_cursor.png differ diff --git a/krita/plugins/tools/selectiontools/tool_contiguous_selection.png b/krita/plugins/tools/selectiontools/tool_contiguous_selection.png new file mode 100644 index 00000000..84a3053f Binary files /dev/null and b/krita/plugins/tools/selectiontools/tool_contiguous_selection.png differ diff --git a/krita/plugins/tools/selectiontools/tool_contiguous_selection_cursor.png b/krita/plugins/tools/selectiontools/tool_contiguous_selection_cursor.png new file mode 100644 index 00000000..ca982c47 Binary files /dev/null and b/krita/plugins/tools/selectiontools/tool_contiguous_selection_cursor.png differ diff --git a/krita/plugins/tools/selectiontools/tool_elliptical_selection.png b/krita/plugins/tools/selectiontools/tool_elliptical_selection.png new file mode 100644 index 00000000..9ae547f6 Binary files /dev/null and b/krita/plugins/tools/selectiontools/tool_elliptical_selection.png differ diff --git a/krita/plugins/tools/selectiontools/tool_elliptical_selection.svg b/krita/plugins/tools/selectiontools/tool_elliptical_selection.svg new file mode 100644 index 00000000..813140bc --- /dev/null +++ b/krita/plugins/tools/selectiontools/tool_elliptical_selection.svg @@ -0,0 +1,256 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/krita/plugins/tools/selectiontools/tool_elliptical_selection_cursor.png b/krita/plugins/tools/selectiontools/tool_elliptical_selection_cursor.png new file mode 100644 index 00000000..0a903935 Binary files /dev/null and b/krita/plugins/tools/selectiontools/tool_elliptical_selection_cursor.png differ diff --git a/krita/plugins/tools/selectiontools/tool_eraser_selection.png b/krita/plugins/tools/selectiontools/tool_eraser_selection.png new file mode 100644 index 00000000..099d9b72 Binary files /dev/null and b/krita/plugins/tools/selectiontools/tool_eraser_selection.png differ diff --git a/krita/plugins/tools/selectiontools/tool_eraser_selection.svg b/krita/plugins/tools/selectiontools/tool_eraser_selection.svg new file mode 100644 index 00000000..c701e988 --- /dev/null +++ b/krita/plugins/tools/selectiontools/tool_eraser_selection.svg @@ -0,0 +1,1993 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/krita/plugins/tools/selectiontools/tool_eraser_selection_cursor.png b/krita/plugins/tools/selectiontools/tool_eraser_selection_cursor.png new file mode 100644 index 00000000..1b2e6a36 Binary files /dev/null and b/krita/plugins/tools/selectiontools/tool_eraser_selection_cursor.png differ diff --git a/krita/plugins/tools/selectiontools/tool_outline_selection.png b/krita/plugins/tools/selectiontools/tool_outline_selection.png new file mode 100644 index 00000000..e7aab4c7 Binary files /dev/null and b/krita/plugins/tools/selectiontools/tool_outline_selection.png differ diff --git a/krita/plugins/tools/selectiontools/tool_outline_selection.svg b/krita/plugins/tools/selectiontools/tool_outline_selection.svg new file mode 100644 index 00000000..c13da38d --- /dev/null +++ b/krita/plugins/tools/selectiontools/tool_outline_selection.svg @@ -0,0 +1,329 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/krita/plugins/tools/selectiontools/tool_outline_selection_cursor.png b/krita/plugins/tools/selectiontools/tool_outline_selection_cursor.png new file mode 100644 index 00000000..af07aa5b Binary files /dev/null and b/krita/plugins/tools/selectiontools/tool_outline_selection_cursor.png differ diff --git a/krita/plugins/tools/selectiontools/tool_polygonal_selection.png b/krita/plugins/tools/selectiontools/tool_polygonal_selection.png new file mode 100644 index 00000000..555320e6 Binary files /dev/null and b/krita/plugins/tools/selectiontools/tool_polygonal_selection.png differ diff --git a/krita/plugins/tools/selectiontools/tool_polygonal_selection.svg b/krita/plugins/tools/selectiontools/tool_polygonal_selection.svg new file mode 100644 index 00000000..81e675ea --- /dev/null +++ b/krita/plugins/tools/selectiontools/tool_polygonal_selection.svg @@ -0,0 +1,364 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/krita/plugins/tools/selectiontools/tool_polygonal_selection_cursor.png b/krita/plugins/tools/selectiontools/tool_polygonal_selection_cursor.png new file mode 100644 index 00000000..1da7ee1a Binary files /dev/null and b/krita/plugins/tools/selectiontools/tool_polygonal_selection_cursor.png differ diff --git a/krita/plugins/tools/selectiontools/tool_rect_selection.png b/krita/plugins/tools/selectiontools/tool_rect_selection.png new file mode 100644 index 00000000..0d9dacf4 Binary files /dev/null and b/krita/plugins/tools/selectiontools/tool_rect_selection.png differ diff --git a/krita/plugins/tools/selectiontools/tool_rect_selection.svg b/krita/plugins/tools/selectiontools/tool_rect_selection.svg new file mode 100644 index 00000000..0ce19bc1 --- /dev/null +++ b/krita/plugins/tools/selectiontools/tool_rect_selection.svg @@ -0,0 +1,191 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/krita/plugins/tools/selectiontools/tool_rectangular_selection_cursor.png b/krita/plugins/tools/selectiontools/tool_rectangular_selection_cursor.png new file mode 100644 index 00000000..57444a70 Binary files /dev/null and b/krita/plugins/tools/selectiontools/tool_rectangular_selection_cursor.png differ diff --git a/krita/plugins/tools/tool_crop/Makefile.am b/krita/plugins/tools/tool_crop/Makefile.am new file mode 100644 index 00000000..b9c2fad4 --- /dev/null +++ b/krita/plugins/tools/tool_crop/Makefile.am @@ -0,0 +1,36 @@ +kde_services_DATA = kritatoolcrop.desktop + +# all_includes must remain last! +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kritatoolcrop_la_SOURCES = \ + wdg_tool_crop.ui \ + tool_crop.cc \ + kis_tool_crop.cc + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = kritatoolcrop.la + +noinst_HEADERS = \ + tool_crop.h \ + kis_tool_crop.h + +kritatoolcrop_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritatoolcrop_la_LIBADD = ../../../libkritacommon.la + +kritatoolcrop_la_METASOURCES = AUTO + +KDE_OPTIONS = nofinal + +kritapics_DATA = \ + tool_crop_cursor.png \ + tool_crop.png + +kritapicsdir = $(kde_datadir)/krita/pics + diff --git a/krita/plugins/tools/tool_crop/kis_tool_crop.cc b/krita/plugins/tools/tool_crop/kis_tool_crop.cc new file mode 100644 index 00000000..fd83e204 --- /dev/null +++ b/krita/plugins/tools/tool_crop/kis_tool_crop.cc @@ -0,0 +1,925 @@ +/* + * kis_tool_crop.cc -- part of Krita + * + * 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 = QRect(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, QRect()); +} + +void KisToolCrop::paint(KisCanvasPainter& gc, const QRect& 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 = QRect(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() == LeftButton) { + + QPoint pos = e->pos().floorQPoint(); + QRect 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 = QRect( 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().floorQPoint()); + + KisImageSP image = m_subject->currentImg(); + + m_rectCrop.setRight( QMIN(m_rectCrop.right(), image->width())); + m_rectCrop.setBottom( QMIN(m_rectCrop.bottom(), image->width())); + m_rectCrop = m_rectCrop.normalize(); + + paintOutlineWithHandles(); + } + else //if the crop selection is set + { + m_dragStop = e->pos().floorQPoint(); + if (m_mouseOnHandleType != None && m_dragStart != m_dragStop ) { + + + Q_INT32 imageWidth = m_subject->currentImg()->width(); + Q_INT32 imageHeight = m_subject->currentImg()->height(); + + paintOutlineWithHandles(); + + QPoint pos = e->pos().floorQPoint(); + 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()) + { + QPoint drag = m_dragStop - m_dragStart; + if( ! m_optWidget->boolWidth->isChecked() && !m_optWidget->boolHeight->isChecked() ) + { + switch (m_mouseOnHandleType) + { + case (UpperLeft): + { + Q_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): + { + Q_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): + { + Q_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): + { + Q_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( QRect(0,0, imageWidth + 1, imageHeight + 1 ) ); + m_dragStart = e->pos().floorQPoint(); + paintOutlineWithHandles(); + } + } + updateWidgetValues(); + } + else //if we are not selecting + { + if ( m_haveCropSelection ) //if the crop selection is set + { + KisCanvasController *controller = m_subject->canvasController(); + Q_INT32 type = mouseOnHandle(controller->windowToView(e->pos().floorQPoint())); + //set resize cursor if we are on one of the handles + setMoveResizeCursor(type); + } + } + } +} + +void KisToolCrop::updateWidgetValues(bool updateratio) +{ + QRect 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() == 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) { + Q_INT32 imageWidth = image->width(); + Q_INT32 imageHeight = image->height(); + m_rectCrop.setLeft(QMAX(0, m_rectCrop.left())); + m_rectCrop.setTop(QMAX(0, m_rectCrop.top())); + m_rectCrop.setRight(QMIN(imageWidth, m_rectCrop.right())); + m_rectCrop.setBottom(QMIN(imageHeight, m_rectCrop.bottom())); + + updateWidgetValues(updateratio); + } + } +} + +void KisToolCrop::paintOutlineWithHandles() +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + KisCanvas *canvas = controller->kiscanvas(); + KisCanvasPainter gc(canvas); + QRect rc; + + paintOutlineWithHandles(gc, rc); + } +} + +void KisToolCrop::paintOutlineWithHandles(KisCanvasPainter& gc, const QRect&) +{ + if (m_subject && (m_selecting || m_haveCropSelection)) { + KisCanvasController *controller = m_subject->canvasController(); + RasterOp op = gc.rasterOp(); + QPen old = gc.pen(); + QPen pen(Qt::SolidLine); + pen.setWidth(1); + QPoint start; + QPoint end; + + Q_ASSERT(controller); + start = controller->windowToView(m_rectCrop.topLeft()); + end = controller->windowToView(m_rectCrop.bottomRight()); + + gc.setRasterOp(Qt::NotROP); + gc.setPen(pen); + //draw handles + m_handlesRegion = handles(QRect(start, end)); + + Q_INT32 startx; + Q_INT32 starty; + Q_INT32 endx; + Q_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); + QMemArray rects = m_handlesRegion.rects (); + for (QMemArray ::ConstIterator it = rects.begin (); it != rects.end (); ++it) + { + gc.fillRect (*it, Qt::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; + + QRect rc = realRectCrop().normalize(); + + // The visitor adds the undo steps to the macro + if (m_optWidget->cmbType->currentItem() == 0) { + + QRect 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 = QRect(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(Q_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(Q_INT32 y) +{ + m_optWidget->intY->blockSignals(true); + m_optWidget->intY->setValue(y); + m_optWidget->intY->blockSignals(false); +} + +void KisToolCrop::setOptionWidgetWidth(Q_INT32 x) +{ + m_optWidget->intWidth->blockSignals(true); + m_optWidget->intWidth->setValue(x); + m_optWidget->intWidth->blockSignals(false); +} + +void KisToolCrop::setOptionWidgetHeight(Q_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); +} + + +QWidget* KisToolCrop::createOptionWidget(QWidget* parent) +{ + m_optWidget = new WdgToolCrop(parent); + Q_CHECK_PTR(m_optWidget); + + connect(m_optWidget->bnCrop, SIGNAL(clicked()), this, SLOT(crop())); + + connect(m_optWidget->intX, SIGNAL(valueChanged(int)), this, SLOT(setCropX(int))); + connect(m_optWidget->intY, SIGNAL(valueChanged(int)), this, SLOT(setCropY(int))); + connect(m_optWidget->intWidth, SIGNAL(valueChanged(int)), this, SLOT(setCropWidth(int))); + connect(m_optWidget->intHeight, SIGNAL(valueChanged(int)), this, SLOT(setCropHeight(int))); + connect(m_optWidget->doubleRatio, SIGNAL(valueChanged(double)), this, SLOT(setRatio( double ))); + + return m_optWidget; +} + +QWidget* 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, + SLOT(activate()), + collection, + name()); + Q_CHECK_PTR(m_action); + + m_action->setToolTip(i18n("Crop an area")); + m_action->setExclusiveGroup("tools"); + + m_ownAction = true; + } +} + +QRect toQRect(double x, double y, int w, int h) +{ + return QRect(int(x), int(y), w, h); +} + +QRegion KisToolCrop::handles(QRect rect) +{ + QRegion handlesRegion; + + //add handle at the lower right corner + handlesRegion += toQRect( QABS( rect.width() ) - m_handleSize / 2.0, QABS( rect.height() ) - m_handleSize / 2.0, m_handleSize, m_handleSize ); + //add handle at the upper right corner + handlesRegion += toQRect( QABS( rect.width() ) - m_handleSize / 2.0 , 0 - m_handleSize / 2.0, m_handleSize, m_handleSize ); + //add rectangle at the lower left corner + handlesRegion += toQRect( 0 - m_handleSize / 2.0 , QABS( rect.height() ) - m_handleSize / 2.0, m_handleSize, m_handleSize ); + //add rectangle at the upper left corner + handlesRegion += toQRect( 0 - m_handleSize / 2.0, 0 - m_handleSize / 2.0, m_handleSize, m_handleSize ); + //add handle at the lower edge of the rectangle + handlesRegion += toQRect( ( QABS( rect.width() ) - m_handleSize ) / 2.0 , QABS( rect.height() ) - m_handleSize / 2.0, m_handleSize, m_handleSize ); + //add handle at the right edge of the rectangle + handlesRegion += toQRect( QABS( rect.width() ) - m_handleSize / 2.0 , ( QABS( rect.height() ) - m_handleSize ) / 2.0, m_handleSize, m_handleSize ); + //add handle at the upper edge of the rectangle + handlesRegion += toQRect( ( QABS( 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 += toQRect( 0 - m_handleSize / 2.0, ( QABS( 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() - QABS( rect.width() ), rect.y() ); + } + else if( rect.width() >= 0 && rect.height() < 0) + { + handlesRegion.translate ( rect.x(), rect.y() - QABS( rect.height() ) ); + } + else if( rect.width() < 0 && rect.height() < 0) + { + handlesRegion.translate ( rect.x() - QABS( rect.width() ), rect.y() - QABS( rect.height() ) ); + } + return handlesRegion; +} + +Q_INT32 KisToolCrop::mouseOnHandle(QPoint currentViewPoint) +{ + KisCanvasController *controller = m_subject->canvasController(); + Q_ASSERT(controller); + QPoint start = controller->windowToView(m_rectCrop.topLeft()); + QPoint end = controller->windowToView(m_rectCrop.bottomRight()); + + Q_INT32 startx; + Q_INT32 starty; + Q_INT32 endx; + Q_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 ( toQRect ( startx - m_handleSize / 2.0, starty - m_handleSize / 2.0, m_handleSize, m_handleSize ).contains( currentViewPoint ) ) + { + if( !m_selecting ) + { + m_dx= startx-currentViewPoint.x(); + m_dy = starty - currentViewPoint.y(); + } + return UpperLeft; + } + else if ( toQRect ( startx - m_handleSize / 2.0, endy - m_handleSize / 2.0, m_handleSize, m_handleSize ).contains( currentViewPoint ) ) + { + if( !m_selecting ) + { + m_dx = startx-currentViewPoint.x(); + m_dy = endy-currentViewPoint.y(); + } + return LowerLeft; + } + else if ( toQRect ( endx - m_handleSize / 2.0, starty - m_handleSize / 2.0, m_handleSize, m_handleSize ).contains( currentViewPoint ) ) + { + if( !m_selecting ) + { + m_dx = endx - currentViewPoint.x(); + m_dy = starty - currentViewPoint.y() ; + } + return UpperRight; + } + else if ( toQRect ( endx - m_handleSize / 2.0, endy - m_handleSize / 2.0, m_handleSize, m_handleSize ).contains( currentViewPoint ) ) + { + if( !m_selecting ) + { + m_dx = endx - currentViewPoint.x(); + m_dy= endy - currentViewPoint.y(); + } + return LowerRight; + } + else if ( toQRect ( startx + ( endx - startx - m_handleSize ) / 2.0, starty - m_handleSize / 2.0, m_handleSize, m_handleSize ).contains( currentViewPoint ) ) + { + if( !m_selecting ) + { + m_dy = starty - currentViewPoint.y() ; + } + return Upper; + } + else if ( toQRect ( startx + ( endx - startx - m_handleSize ) / 2.0, endy - m_handleSize / 2, m_handleSize, m_handleSize ).contains( currentViewPoint ) ) + { + if( !m_selecting ) + { + m_dy = endy - currentViewPoint.y(); + } + return Lower; + } + else if ( toQRect ( startx - m_handleSize / 2.0, starty + ( endy - starty - m_handleSize ) / 2.0, m_handleSize, m_handleSize ).contains( currentViewPoint ) ) + { + if( !m_selecting ) + { + m_dx = startx - currentViewPoint.x() ; + } + return Left; + } + else if ( toQRect ( endx - m_handleSize / 2.0 , starty + ( endy - starty - m_handleSize ) / 2.0, m_handleSize, m_handleSize ).contains( currentViewPoint ) ) + { + if( !m_selecting ) + { + m_dx = endx-currentViewPoint.x(); + } + return Right; + } + else if ( toQRect ( startx , starty, endx - startx , endy - starty ).contains( currentViewPoint ) ) + { + return Inside; + } + else return None; +} + +void KisToolCrop::setMoveResizeCursor (Q_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/krita/plugins/tools/tool_crop/kis_tool_crop.h b/krita/plugins/tools/tool_crop/kis_tool_crop.h new file mode 100644 index 00000000..538e4158 --- /dev/null +++ b/krita/plugins/tools/tool_crop/kis_tool_crop.h @@ -0,0 +1,148 @@ +/* + * kis_tool_crop.h - part of Krita + * + * 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 QRect; +class QCursor; +class WdgToolCrop; + +/** + * Crop tool + * + * TODO: - crop from selection -- i.e, set crop outline to the exact bounds of the selection. + * - (when moving to Qt 4: replace rectangle with darker, dimmer overlay layer + * like we have for selections right now) + */ +class KisToolCrop : public KisToolNonPaint { + + typedef KisToolNonPaint super; + Q_OBJECT + +public: + + KisToolCrop(); + virtual ~KisToolCrop(); + + virtual void update(KisCanvasSubject *subject); + + virtual QWidget* createOptionWidget(QWidget* parent); + virtual QWidget* optionWidget(); + + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_TRANSFORM; } + virtual Q_UINT32 priority() { return 1; } + virtual void paint(KisCanvasPainter& gc); + virtual void paint(KisCanvasPainter& gc, const QRect& 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(); + QRegion handles(QRect rect); + void paintOutlineWithHandles(); + void paintOutlineWithHandles(KisCanvasPainter& gc, const QRect& rc); + Q_INT32 mouseOnHandle (const QPoint currentViewPoint); + void setMoveResizeCursor (Q_INT32 handle); + void validateSelection(bool updateratio = true); + void setOptionWidgetX(Q_INT32 x); + void setOptionWidgetY(Q_INT32 y); + void setOptionWidgetWidth(Q_INT32 x); + void setOptionWidgetHeight(Q_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 QRect realRectCrop() { QRect r = m_rectCrop; r.setSize(r.size() - QSize(1,1)); return r; } + +private: + void updateWidgetValues(bool updateratio = true); + KisCanvasSubject *m_subject; + QRect 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 +// QPoint m_startPos; +// QPoint m_endPos; + bool m_selecting; + QPoint m_dragStart; + QPoint m_dragStop; + + WdgToolCrop* m_optWidget; + + Q_INT32 m_handleSize; + QRegion m_handlesRegion; + bool m_haveCropSelection; + Q_INT32 m_dx, m_dy; + Q_INT32 m_mouseOnHandleType; + QCursor 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/krita/plugins/tools/tool_crop/kritatoolcrop.desktop b/krita/plugins/tools/tool_crop/kritatoolcrop.desktop new file mode 100644 index 00000000..c1fc83e3 --- /dev/null +++ b/krita/plugins/tools/tool_crop/kritatoolcrop.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=Krita/Tool +Type=Service +X-KDE-Library=kritatoolcrop +X-Krita-Version=2 diff --git a/krita/plugins/tools/tool_crop/tool_crop.cc b/krita/plugins/tools/tool_crop/tool_crop.cc new file mode 100644 index 00000000..542af31b --- /dev/null +++ b/krita/plugins/tools/tool_crop/tool_crop.cc @@ -0,0 +1,62 @@ +/* + * tool_crop.cc -- Part of Krita + * + * 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( kritatoolcrop, ToolCropFactory( "krita" ) ) + + +ToolCrop::ToolCrop(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(ToolCropFactory::instance()); + + if ( parent->inherits("KisToolRegistry") ) + { + KisToolRegistry * r = dynamic_cast(parent); + r->add(new KisToolCropFactory()); + } + +} + +ToolCrop::~ToolCrop() +{ +} + +#include "tool_crop.moc" diff --git a/krita/plugins/tools/tool_crop/tool_crop.h b/krita/plugins/tools/tool_crop/tool_crop.h new file mode 100644 index 00000000..1ebe9064 --- /dev/null +++ b/krita/plugins/tools/tool_crop/tool_crop.h @@ -0,0 +1,42 @@ +/* + * 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 +public: + ToolCrop(QObject *parent, const char *name, const QStringList &); + virtual ~ToolCrop(); + +private: + + KisView * m_view; + +}; + +#endif // TOOL_CROP_H_ diff --git a/krita/plugins/tools/tool_crop/tool_crop.png b/krita/plugins/tools/tool_crop/tool_crop.png new file mode 100644 index 00000000..dd94be5c Binary files /dev/null and b/krita/plugins/tools/tool_crop/tool_crop.png differ diff --git a/krita/plugins/tools/tool_crop/tool_crop_cursor.png b/krita/plugins/tools/tool_crop/tool_crop_cursor.png new file mode 100644 index 00000000..44685637 Binary files /dev/null and b/krita/plugins/tools/tool_crop/tool_crop_cursor.png differ diff --git a/krita/plugins/tools/tool_crop/wdg_tool_crop.ui b/krita/plugins/tools/tool_crop/wdg_tool_crop.ui new file mode 100644 index 00000000..8099af7c --- /dev/null +++ b/krita/plugins/tools/tool_crop/wdg_tool_crop.ui @@ -0,0 +1,216 @@ + +WdgToolCrop + + + WdgToolCrop + + + + 0 + 0 + 346 + 123 + + + + Crop + + + + unnamed + + + 0 + + + 0 + + + + layout3 + + + + 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 + + + + + + + layout9 + + + + 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/krita/plugins/tools/tool_curves/Makefile.am b/krita/plugins/tools/tool_curves/Makefile.am new file mode 100644 index 00000000..d809eaee --- /dev/null +++ b/krita/plugins/tools/tool_curves/Makefile.am @@ -0,0 +1,55 @@ +kde_services_DATA = kritatoolcurves.desktop + +# all_includes must remain last! +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kritatoolcurves_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 = kritatoolcurves.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 + +kritatoolcurves_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritatoolcurves_la_LIBADD = ../../../libkritacommon.la + +kritatoolcurves_la_METASOURCES = AUTO + +KDE_OPTIONS = nofinal + +kritapics_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 + +kritapicsdir = $(kde_datadir)/krita/pics + diff --git a/krita/plugins/tools/tool_curves/kis_curve_framework.cc b/krita/plugins/tools/tool_curves/kis_curve_framework.cc new file mode 100644 index 00000000..2ccb87a4 --- /dev/null +++ b/krita/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(find(tend).previousPivot(),find(tend)); +} + +KisCurve KisCurve::subCurve(const CurvePoint& tend) +{ + return subCurve(find(tend).previousPivot(),find(tend)); +} + +KisCurve KisCurve::subCurve(iterator tend) +{ + return subCurve(tend.previousPivot(),tend); +} + +KisCurve KisCurve::subCurve(const KisPoint& tstart, const KisPoint& tend) +{ + return subCurve(find(tstart),find(tend)); +} + +KisCurve KisCurve::subCurve(const CurvePoint& tstart, const CurvePoint& tend) +{ + return subCurve(find(tstart),find(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 (find(pos1),find(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(find(CurvePoint(pt,true)),isSelected); +} + +KisCurve::iterator KisCurve::selectPivot(const CurvePoint& pt, bool isSelected) +{ + return selectPivot(find(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++) + (*find((*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(find(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(find(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/krita/plugins/tools/tool_curves/kis_curve_framework.h b/krita/plugins/tools/tool_curves/kis_curve_framework.h new file mode 100644 index 00000000..23e326c8 --- /dev/null +++ b/krita/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 QValueList PointList; +typedef QValueList::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 find(const CurvePoint& pt); + iterator find(const KisPoint& pt); + iterator find(iterator it, const CurvePoint& pt); + iterator find(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::find (const CurvePoint& pt) +{ + return iterator(*this,m_curve.find(pt)); +} + +inline KisCurve::iterator KisCurve::find (const KisPoint& pt) +{ + return iterator(*this,m_curve.find(CurvePoint(pt))); +} + +inline KisCurve::iterator KisCurve::find (KisCurve::iterator it, const CurvePoint& pt) +{ + return iterator(*this,m_curve.find(it.position(),pt)); +} + +inline KisCurve::iterator KisCurve::find (iterator it, const KisPoint& pt) +{ + return iterator(*this,m_curve.find(it.position(),CurvePoint(pt))); +} + +inline void KisCurve::calculateCurve(const KisPoint& start, const KisPoint& end, KisCurve::iterator it) +{ + calculateCurve(find(CurvePoint(start)),find(CurvePoint(end)),it); +} + +inline void KisCurve::calculateCurve(const CurvePoint& start, const CurvePoint& end, KisCurve::iterator it) +{ + calculateCurve(find(start),find(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/krita/plugins/tools/tool_curves/kis_tool_bezier.cc b/krita/plugins/tools/tool_curves/kis_tool_bezier.cc new file mode 100644 index 00000000..b6d16f78 --- /dev/null +++ b/krita/plugins/tools/tool_curves/kis_tool_bezier.cc @@ -0,0 +1,366 @@ +/* + * kis_tool_bezier.cc -- part of Krita + * + * 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 QString& 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 QPoint& pos) +{ + QPoint 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().toQPoint()); + hint = (*it).hint(); + if (hint != BEZIERENDHINT && !m_derivated->groupSelected(it)) + continue; + if (hint == BEZIERENDHINT && (m_actionOptions & SHIFTOPTION)) + continue; + if (pivotRect(qpos).contains(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->find(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; + QPointArray vec(4); + vec[0] = controller->windowToView((*origin).point().toQPoint()); + vec[1] = controller->windowToView((*control1).point().toQPoint()); + vec[2] = controller->windowToView((*control2).point().toQPoint()); + vec[3] = controller->windowToView((*destination).point().toQPoint()); + 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(); + + QPoint endpPos = controller->windowToView((*point).point().toQPoint()); + + if (!m_derivated->groupSelected(point)) { + gc.setPen(m_pivotPen); + gc.drawRoundRect(pivotRect(endpPos),m_pivotRounding,m_pivotRounding); + } else { + QPoint nextControlPos = controller->windowToView((*point.next()).point().toQPoint()); + QPoint prevControlPos = controller->windowToView((*point.previousPivot()).point().toQPoint()); + + 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/krita/plugins/tools/tool_curves/kis_tool_bezier.h b/krita/plugins/tools/tool_curves/kis_tool_bezier.h new file mode 100644 index 00000000..ec4ce7bb --- /dev/null +++ b/krita/plugins/tools/tool_curves/kis_tool_bezier.h @@ -0,0 +1,97 @@ +/* + * kis_tool_bezier.h -- part of Krita + * + * 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 + +public: + KisToolBezier(const QString&); + virtual ~KisToolBezier(); + +protected: + + virtual KisCurve::iterator handleUnderMouse(const QPoint& 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/krita/plugins/tools/tool_curves/kis_tool_bezier_paint.cc b/krita/plugins/tools/tool_curves/kis_tool_bezier_paint.cc new file mode 100644 index 00000000..94ee2b79 --- /dev/null +++ b/krita/plugins/tools/tool_curves/kis_tool_bezier_paint.cc @@ -0,0 +1,115 @@ +/* + * kis_tool_curve.cc -- part of Krita + * + * 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(Qt::Key_Plus); + shortcut.append(KShortcut(Qt::Key_F9)); + m_action = new KRadioAction(i18n("&Bezier"), + "tool_bezier_paint", + shortcut, + this, + 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/krita/plugins/tools/tool_curves/kis_tool_bezier_paint.h b/krita/plugins/tools/tool_curves/kis_tool_bezier_paint.h new file mode 100644 index 00000000..052f23e6 --- /dev/null +++ b/krita/plugins/tools/tool_curves/kis_tool_bezier_paint.h @@ -0,0 +1,62 @@ +/* + * kis_tool_curve_paint.h -- part of Krita + * + * 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 + +public: + KisToolBezierPaint(); + virtual ~KisToolBezierPaint(); + + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_SHAPE; } + virtual Q_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("beziershape", i18n("Bezier Painting Tool")); } +}; + +#endif //__KIS_TOOL_CURVE_PAINT_H_ diff --git a/krita/plugins/tools/tool_curves/kis_tool_bezier_select.cc b/krita/plugins/tools/tool_curves/kis_tool_bezier_select.cc new file mode 100644 index 00000000..94ebde37 --- /dev/null +++ b/krita/plugins/tools/tool_curves/kis_tool_bezier_select.cc @@ -0,0 +1,104 @@ +/* + * kis_tool_curve.cc -- part of Krita + * + * 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() +{ + +} + +QValueVector KisToolBezierSelect::convertCurve() +{ + QValueVector 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(Qt::Key_Plus); + shortcut.append(KShortcut(Qt::Key_F9)); + m_action = new KRadioAction(i18n("&Bezier"), + "tool_bezier_select", + shortcut, + this, + 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/krita/plugins/tools/tool_curves/kis_tool_bezier_select.h b/krita/plugins/tools/tool_curves/kis_tool_bezier_select.h new file mode 100644 index 00000000..ac596eeb --- /dev/null +++ b/krita/plugins/tools/tool_curves/kis_tool_bezier_select.h @@ -0,0 +1,62 @@ +/* + * kis_tool_curve_paint.h -- part of Krita + * + * 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 + +public: + KisToolBezierSelect(); + virtual ~KisToolBezierSelect(); + + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_SELECT; } + virtual Q_UINT32 priority() { return 10; } + +protected: + + virtual QValueVector 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/krita/plugins/tools/tool_curves/kis_tool_curve.cc b/krita/plugins/tools/tool_curves/kis_tool_curve.cc new file mode 100644 index 00000000..526311e3 --- /dev/null +++ b/krita/plugins/tools/tool_curves/kis_tool_curve.cc @@ -0,0 +1,593 @@ +/* + * kis_tool_curve.cc -- part of Krita + * + * 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" + +QRect KisToolCurve::pivotRect (const QPoint& pos) +{ + return QRect (pos-QPoint(4,4),pos+QPoint(4,4)); +} + +QRect KisToolCurve::selectedPivotRect (const QPoint& pos) +{ + return QRect (pos-QPoint(5,5),pos+QPoint(5,5)); +} + +KisToolCurve::KisToolCurve(const QString& 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 = QPen(Qt::white, 0, Qt::SolidLine); + m_pivotPen = QPen(Qt::gray, 0, Qt::SolidLine); + m_selectedPivotPen = QPen(Qt::yellow, 0, Qt::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().toQPoint())); + 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->find(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(QKeyEvent *event) +{ + if (event->key() == Qt::Key_Return) { + m_dragging = false; + commitCurve(); + } else + if (event->key() == Qt::Key_Escape) { + m_dragging = false; + draw(false); + m_curve->clear(); + } else + if (event->key() == Qt::Key_Delete) { + draw(false); + m_dragging = false; + m_curve->deleteSelected(); + m_current = m_curve->find(m_curve->last()); + m_previous = m_curve->selectPivot(m_current); + draw(false); + } +} + +void KisToolCurve::keyRelease(QKeyEvent *) +{ + +} + +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().toQPoint())); + 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 QPoint& pos) +{ + KisCurve::iterator it, next; + QPoint 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().toQPoint()); + pos2 = m_subject->canvasController()->windowToView((*next).point().toQPoint()); + if (pos1 == pos2) + continue; + if (pointToSegmentDistance(pos,pos1,pos2) <= MAXDISTANCE) + break; + } + + return PointPair(it,false); +} + +KisCurve::iterator KisToolCurve::handleUnderMouse(const QPoint& 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().toQPoint())).contains(pos)) + inHandle.pushPoint((*it)); + } + if (inHandle.isEmpty()) + return m_curve->end(); + return m_curve->find(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 & Qt::ControlButton) + options |= CONTROLOPTION; + + if (key & Qt::ShiftButton) + options |= SHIFTOPTION; + + if (key & Qt::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(Qt::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->find(*i).previousPivot(); + finish = m_curve->find(*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(); + + QPoint pos1, pos2; + pos1 = controller->windowToView((*point).point().toQPoint()); + + 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().toQPoint()); + 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) { + QPoint pos = controller->windowToView((*point).point().toQPoint()); + 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 QRect&) +{ + 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; +} + +QValueVector KisToolCurve::convertCurve() +{ + QValueVector 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() +{ + QApplication::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(Qt::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) { + QRect dirty(painter.dirtyRect()); + dev->setDirty(dirty); + dev->emitSelectionChanged(dirty); + } else { + dev->setDirty(); + dev->emitSelectionChanged(); + } + + if (m_currentImage->undo()) + m_currentImage->undoAdapter()->addCommand(t); + + QApplication::restoreOverrideCursor(); + + draw(false); +} + +QWidget* KisToolCurve::createOptionWidget(QWidget* parent) +{ + if (toolType() == TOOL_SHAPE || toolType() == TOOL_FREEHAND) + return super::createOptionWidget(parent); + else if (toolType() == TOOL_SELECT) + return createSelectionOptionWidget(parent); + 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; +} + +QWidget* KisToolCurve::createSelectionOptionWidget(QWidget* parent) +{ + m_optWidget = new KisSelectionOptions(parent, m_subject); + Q_CHECK_PTR(m_optWidget); + m_optWidget->setCaption(m_UIName); + + connect (m_optWidget, SIGNAL(actionChanged(int)), this, SLOT(slotSetAction(int))); + + QVBoxLayout * l = dynamic_cast(m_optWidget->layout()); + l->addItem(new QSpacerItem(1, 1, QSizePolicy::Fixed, QSizePolicy::Expanding)); + + return m_optWidget; +} + +QWidget* KisToolCurve::optionWidget() +{ + if (toolType() == TOOL_SELECT) + return m_optWidget; + else + return super::optionWidget(); +} + +#include "kis_tool_curve.moc" diff --git a/krita/plugins/tools/tool_curves/kis_tool_curve.h b/krita/plugins/tools/tool_curves/kis_tool_curve.h new file mode 100644 index 00000000..17a0c418 --- /dev/null +++ b/krita/plugins/tools/tool_curves/kis_tool_curve.h @@ -0,0 +1,204 @@ +/* + * kis_tool_curve.h -- part of Krita + * + * 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 QRect; +class KisPainter; +class KisSelectionOptions; + +typedef QPair 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 + +public: + KisToolCurve(const QString& UIName); + virtual ~KisToolCurve(); + + virtual void update (KisCanvasSubject *subject); + virtual QWidget* createOptionWidget(QWidget* parent); + + virtual void buttonPress(KisButtonPressEvent *event); + virtual void move(KisMoveEvent *event); + virtual void buttonRelease(KisButtonReleaseEvent *event); + virtual void doubleClick(KisDoubleClickEvent *event); + virtual void keyPress(QKeyEvent *event); + virtual void keyRelease(QKeyEvent *event); + +public slots: + + virtual void deactivate(); + +protected: + + virtual void paint(KisCanvasPainter&); + virtual void paint(KisCanvasPainter&, const QRect&); + + /* ********************** * + * 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 QPoint& pos); + virtual KisCurve::iterator handleUnderMouse(const QPoint& 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 QValueVector 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 + */ + QRect pivotRect (const QPoint&); + + /* + * Same as above for selected pivots + */ + QRect selectedPivotRect (const QPoint&); + +protected: + + KisImageSP m_currentImage; + + KisCurve *m_curve; + KisCurve::iterator m_current; + KisCurve::iterator m_previous; + KisPoint m_currentPoint; + + bool m_dragging; + bool m_drawPivots; + QPen m_drawingPen; + QPen m_pivotPen; + QPen m_selectedPivotPen; + int m_pivotRounding; + int m_selectedPivotRounding; + + int m_actionOptions; + bool m_supportMinimalDraw; + bool m_draggingCursor; + + QString m_transactionMessage; + QString m_cursor; + +private: + + QString m_UIName; + + +/* ********************************** * + * Selection Tools specific functions * + * ********************************** */ + +public: + + /* + * This initializes our Option Widget (called by createOptionWidget()) + */ + virtual QWidget* createSelectionOptionWidget(QWidget* parent); + + /* + * This return our internal KisSelectionOptions if toolType() returns TOOL_SELECT + */ + virtual QWidget* 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/krita/plugins/tools/tool_curves/kis_tool_example.cc b/krita/plugins/tools/tool_curves/kis_tool_example.cc new file mode 100644 index 00000000..9fcc5d01 --- /dev/null +++ b/krita/plugins/tools/tool_curves/kis_tool_example.cc @@ -0,0 +1,108 @@ +/* + * kis_tool_example.cc -- part of Krita + * + * 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(Qt::Key_Plus); + shortcut.append(KShortcut(Qt::Key_F9)); + m_action = new KRadioAction(i18n("&Example"), + "tool_example", + shortcut, + this, + 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/krita/plugins/tools/tool_curves/kis_tool_example.h b/krita/plugins/tools/tool_curves/kis_tool_example.h new file mode 100644 index 00000000..af1d3574 --- /dev/null +++ b/krita/plugins/tools/tool_curves/kis_tool_example.h @@ -0,0 +1,66 @@ +/* + * kis_tool_example.h -- part of Krita + * + * 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 + +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("exampleshape", i18n("Example Tool")); } +}; + + +#endif //__KIS_TOOL_EXAMPLE_H__ diff --git a/krita/plugins/tools/tool_curves/kis_tool_moutline.cc b/krita/plugins/tools/tool_curves/kis_tool_moutline.cc new file mode 100644 index 00000000..75ab0205 --- /dev/null +++ b/krita/plugins/tools/tool_curves/kis_tool_moutline.cc @@ -0,0 +1,809 @@ +/* + * kis_tool_moutline.cc -- part of Krita + * + * 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 { + + QPoint m_pos; + int m_gCost; + int m_hCost; + int m_tCost; + bool m_malus; + QPoint m_parent; + +public: + + Node() + { + m_pos = m_parent = QPoint(-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.parent(); + } + + Node(const QPoint& parent, const QPoint& pos, int g, int h, bool malus) + : m_pos(pos), m_hCost(h), m_malus(malus) + { + setGCost(g); + m_parent = parent; + } + ~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;} + QPoint pos () const {return m_pos;} + int col () const {return m_pos.x();} + int row () const {return m_pos.y();} + QPoint parent () 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 QPoint& pos) + { + m_pos = pos; + } + void setMalus (bool malus) + { + m_malus = malus; + } + void clear () + { + m_pos = QPoint(-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 QPoint& n2) const + { + return m_pos == n2; + } + bool operator!= (const QPoint& 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(); + } + + QValueList getNeighbor(const GrayMatrix& src, const Node& end) + { + QPoint tmpdist; + QValueList 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 = QPoint(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,QPoint(dcol,drow),g,h,malus)); + } + return temp; + } + +}; + +KisKernelSP createKernel( Q_INT32 i0, Q_INT32 i1, Q_INT32 i2, + Q_INT32 i3, Q_INT32 i4, Q_INT32 i5, + Q_INT32 i6, Q_INT32 i7, Q_INT32 i8, + Q_INT32 factor, Q_INT32 offset ) +{ + KisKernelSP kernel = new KisKernel(); + kernel->width = 3; + kernel->height = 3; + + kernel->factor = factor; + kernel->offset = offset; + + kernel->data = new Q_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 *parent) + : m_parent(parent) +{ + 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; + QPoint start = (*p1).point().roundQPoint(); + QPoint end = (*p2).point().roundQPoint(); + QRect rc = QRect(start,end).normalize(); + rc.setTopLeft(rc.topLeft()+QPoint(-8,-8)); // Enlarge the view, so problems with gaussian blur can be removed + rc.setBottomRight(rc.bottomRight()+QPoint(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())); + + QPoint 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(); + + QValueList successors = current.getNeighbor(dst,endNode); + for (QValueList::iterator i = successors.begin(); i != successors.end(); i++) { + int col = (*i).col(); + int row = (*i).row(); + if ((*i) == endNode) { + while (current.parent() != QPoint(-1,-1)) { + it = addPoint(it,tl+current.pos(),false,false,LINEHINT); + current = closedMatrix[current.parent().x()][current.parent().y()]; + } + return; + } + Node *openNode = &openMatrix[col][row]; + if (*openNode != QPoint(-1,-1)) { + if (*i > *openNode) + continue; + else { + openSet.erase(qFind(openSet.begin(),openSet.end(),*openNode)); + openNode->clear(); // Clear the Node + } + } + Node *closedNode = &closedMatrix[col][row]; + if (*closedNode != QPoint(-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(QPoint(x,y)); +} + +void KisCurveMagnetic::reduceMatrix (QRect& rc, GrayMatrix& m, int top, int right, int bottom, int left) +{ + QPoint topleft(top, left); + QPoint 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 QRect & 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 QRect& 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 QRect& rect, KisPaintDeviceSP src, GrayMatrix& dst) +{ + int grectx = rect.x(); + int grecty = rect.y(); + int grectw = rect.width(); + int grecth = rect.height(); + QColor 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->toQColor(srcIt.rawData(),&c); + dst[col][row] = qGray(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; + Q_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] = (Q_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 + Q_INT16 mag; // Current magnitude + Q_INT16 lmag; // Magnitude at the left (So this pixel is "more internal" than the current + Q_INT16 rmag; // Magnitude at the right (So this pixel is "more external") + double xdel; // Current xdelta + double ydel; // Current ydelta + Q_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(QKeyEvent *event) +{ + if (event->key() == Qt::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() == Qt::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().toQPoint())); + 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().floorQPoint()) + return; + if (m_editingMode) { + PointPair temp = pointUnderMouse(m_subject->canvasController()->windowToView(event->pos().toQPoint())); + 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().floorQPoint(); + 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; +} + +QWidget* KisToolMagnetic::createOptionWidget(QWidget* parent) +{ + m_optWidget = super::createOptionWidget(parent); + QVBoxLayout * l = dynamic_cast(m_optWidget->layout()); + QGridLayout *box = new QGridLayout(l, 2, 2, 3); + box->setColStretch(0, 1); + box->setColStretch(1, 1); + Q_CHECK_PTR(box); + + m_mode = new QLabel(i18n("Automatic mode"), m_optWidget); + m_lbDistance = new QLabel(i18n("Distance: "), m_optWidget); + QPushButton *finish = new QPushButton(i18n("To Selection"), m_optWidget); + m_slDistance = new QSlider(MINDIST, MAXDIST, PAGESTEP, m_distance, Qt::Horizontal, m_optWidget); + + connect(m_slDistance, SIGNAL(valueChanged(int)), this, SLOT(slotSetDistance(int))); + connect(finish, SIGNAL(clicked()), this, 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(Qt::Key_Plus); + shortcut.append(KShortcut(Qt::Key_F9)); + m_action = new KRadioAction(i18n("Magnetic Outline"), + "tool_moutline", + shortcut, + this, + 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/krita/plugins/tools/tool_curves/kis_tool_moutline.h b/krita/plugins/tools/tool_curves/kis_tool_moutline.h new file mode 100644 index 00000000..43a140be --- /dev/null +++ b/krita/plugins/tools/tool_curves/kis_tool_moutline.h @@ -0,0 +1,131 @@ +/* + * kis_tool_moutline.h -- part of Krita + * + * 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 QSlider; +class KisToolMagnetic; +class KisVector2D; +class Node; + +typedef QValueVector NodeCol; +typedef QValueVector NodeMatrix; +typedef QValueVector GrayCol; +typedef QValueVector GrayMatrix; + +class KisCurveMagnetic : public KisCurve { + + typedef KisCurve super; + + KisToolMagnetic *m_parent; + + void reduceMatrix (QRect&, GrayMatrix&, int, int, int, int); + void findEdge (int, int, const GrayMatrix&, Node&); + void detectEdges (const QRect&, KisPaintDeviceSP, GrayMatrix&); + + void gaussianBlur (const QRect&, KisPaintDeviceSP, KisPaintDeviceSP); + void toGrayScale (const QRect&, 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 *parent); + ~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 + + friend class KisCurveMagnetic; + +public: + + KisToolMagnetic(); + ~KisToolMagnetic(); + + virtual void update (KisCanvasSubject*); + virtual void setup (KActionCollection*); + virtual enumToolType toolType() { return TOOL_SELECT; } + virtual Q_UINT32 priority() { return 9; } + + virtual void keyPress(QKeyEvent*); + 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 QWidget* createOptionWidget(QWidget* parent); + +public slots: + + virtual void activate (); + virtual void deactivate (); + + void slotCommitCurve (); + void slotSetDistance (int); + +private: + + KisCurveMagnetic *m_derived; + QWidget* m_optWidget; + QLabel* m_mode; + QLabel* m_lbDistance; + QSlider* 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/krita/plugins/tools/tool_curves/kritatoolcurves.desktop b/krita/plugins/tools/tool_curves/kritatoolcurves.desktop new file mode 100644 index 00000000..60fddc10 --- /dev/null +++ b/krita/plugins/tools/tool_curves/kritatoolcurves.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=Krita/Tool +Type=Service +X-KDE-Library=kritatoolcurves +X-Krita-Version=2 diff --git a/krita/plugins/tools/tool_curves/tool_bezier_cursor.png b/krita/plugins/tools/tool_curves/tool_bezier_cursor.png new file mode 100644 index 00000000..78dae446 Binary files /dev/null and b/krita/plugins/tools/tool_curves/tool_bezier_cursor.png differ diff --git a/krita/plugins/tools/tool_curves/tool_bezier_paint.png b/krita/plugins/tools/tool_curves/tool_bezier_paint.png new file mode 100644 index 00000000..dcbd93d5 Binary files /dev/null and b/krita/plugins/tools/tool_curves/tool_bezier_paint.png differ diff --git a/krita/plugins/tools/tool_curves/tool_bezier_select.png b/krita/plugins/tools/tool_curves/tool_bezier_select.png new file mode 100644 index 00000000..84fb3036 Binary files /dev/null and b/krita/plugins/tools/tool_curves/tool_bezier_select.png differ diff --git a/krita/plugins/tools/tool_curves/tool_curve_dragging.png b/krita/plugins/tools/tool_curves/tool_curve_dragging.png new file mode 100644 index 00000000..e8fb92f4 Binary files /dev/null and b/krita/plugins/tools/tool_curves/tool_curve_dragging.png differ diff --git a/krita/plugins/tools/tool_curves/tool_curves.cc b/krita/plugins/tools/tool_curves/tool_curves.cc new file mode 100644 index 00000000..bb4b2736 --- /dev/null +++ b/krita/plugins/tools/tool_curves/tool_curves.cc @@ -0,0 +1,67 @@ +/* + * tool_bezier.cc -- part of Krita + * + * 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( kritatoolcurves, ToolCurvesFactory( "krita" ) ) + + +ToolCurves::ToolCurves(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(ToolCurvesFactory::instance()); + + if ( parent->inherits("KisToolRegistry") ) + { + KisToolRegistry * r = dynamic_cast( parent ); + r->add(new KisToolBezierPaintFactory()); + r->add(new KisToolBezierSelectFactory()); + r->add(new KisToolMagneticFactory()); + } + +} + +ToolCurves::~ToolCurves() +{ +} + +#include "tool_curves.moc" diff --git a/krita/plugins/tools/tool_curves/tool_curves.h b/krita/plugins/tools/tool_curves/tool_curves.h new file mode 100644 index 00000000..7a097d46 --- /dev/null +++ b/krita/plugins/tools/tool_curves/tool_curves.h @@ -0,0 +1,35 @@ +/* + * tool_bezier.h -- part of Krita + * + * 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 +public: + ToolCurves(QObject *parent, const char *name, const QStringList &); + virtual ~ToolCurves(); + +}; + +#endif // TOOL_BEZIER_H__ diff --git a/krita/plugins/tools/tool_curves/tool_example.png b/krita/plugins/tools/tool_curves/tool_example.png new file mode 100644 index 00000000..02f821ce Binary files /dev/null and b/krita/plugins/tools/tool_curves/tool_example.png differ diff --git a/krita/plugins/tools/tool_curves/tool_example_cursor.png b/krita/plugins/tools/tool_curves/tool_example_cursor.png new file mode 100644 index 00000000..78dae446 Binary files /dev/null and b/krita/plugins/tools/tool_curves/tool_example_cursor.png differ diff --git a/krita/plugins/tools/tool_curves/tool_moutline.png b/krita/plugins/tools/tool_curves/tool_moutline.png new file mode 100644 index 00000000..2f75d945 Binary files /dev/null and b/krita/plugins/tools/tool_curves/tool_moutline.png differ diff --git a/krita/plugins/tools/tool_curves/tool_moutline_cursor.png b/krita/plugins/tools/tool_curves/tool_moutline_cursor.png new file mode 100644 index 00000000..039b9e50 Binary files /dev/null and b/krita/plugins/tools/tool_curves/tool_moutline_cursor.png differ diff --git a/krita/plugins/tools/tool_curves/tool_moutline_editing.png b/krita/plugins/tools/tool_curves/tool_moutline_editing.png new file mode 100644 index 00000000..568d9fd4 Binary files /dev/null and b/krita/plugins/tools/tool_curves/tool_moutline_editing.png differ diff --git a/krita/plugins/tools/tool_curves/wdg_tool_example.ui b/krita/plugins/tools/tool_curves/wdg_tool_example.ui new file mode 100644 index 00000000..3841185f --- /dev/null +++ b/krita/plugins/tools/tool_curves/wdg_tool_example.ui @@ -0,0 +1,128 @@ + +WdgToolExample + + + WdgToolExample + + + + 0 + 0 + 280 + 50 + + + + Example + + + + unnamed + + + 0 + + + + layout8 + + + + unnamed + + + + textLabel1 + + + Vertices: + + + isbX + + + + + verticesSpinBox + + + 100 + + + 2 + + + 5 + + + + + + + layout7 + + + + 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/krita/plugins/tools/tool_filter/Makefile.am b/krita/plugins/tools/tool_filter/Makefile.am new file mode 100644 index 00000000..d43f6b95 --- /dev/null +++ b/krita/plugins/tools/tool_filter/Makefile.am @@ -0,0 +1,37 @@ +kde_services_DATA = kritatoolfilter.desktop + +# all_includes must remain last! +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kritatoolfilter_la_SOURCES = \ + kis_filterop.cc \ + kis_tool_filter.cc \ + tool_filter.cc + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = kritatoolfilter.la + +noinst_HEADERS = \ + kis_filterop.h \ + kis_tool_filter.h \ + tool_filter.h + +kritatoolfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritatoolfilter_la_LIBADD = ../../../libkritacommon.la + +kritatoolfilter_la_METASOURCES = AUTO + +KDE_OPTIONS = nofinal + +kritapics_DATA = \ + tool_filter.png \ + tool_filter_cursor.png + +kritapicsdir = $(kde_datadir)/krita/pics + diff --git a/krita/plugins/tools/tool_filter/kis_filterop.cc b/krita/plugins/tools/tool_filter/kis_filterop.cc new file mode 100644 index 00000000..a2ca604a --- /dev/null +++ b/krita/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. + Q_INT32 x; + double xFraction; + Q_INT32 y; + double yFraction; + + splitCoordinate(pt.x(), &x, &xFraction); + splitCoordinate(pt.y(), &y, &yFraction); + + // Filters always work with a mask, never with an image; that + // wouldn't be useful at all. + KisAlphaMaskSP mask = brush->mask(info, xFraction, yFraction); + + m_painter->setPressure(info.pressure); + + Q_INT32 maskWidth = mask->width(); + Q_INT32 maskHeight = mask->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, maskWidth, maskHeight ); + + // Filter the paint device + filter->disableProgress(); + filter->process( tmpDev, tmpDev, m_filterConfiguration, QRect( 0, 0, maskWidth, maskHeight )); + filter->enableProgress(); + + // Apply the mask on the paint device (filter before mask because edge pixels may be important) + for (int y = 0; y < maskHeight; y++) + { + KisHLineIterator hiter = tmpDev->createHLineIterator(0, y, maskWidth, false); + int x=0; + while(! hiter.isDone()) + { + Q_UINT8 alpha = mask->alphaAt( x++, y ); + colorSpace->setAlpha(hiter.rawData(), alpha, 1); + + ++hiter; + } + } + + // Blit the paint device onto the layer + QRect dabRect = QRect(0, 0, maskWidth, maskHeight); + QRect dstRect = QRect(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; + + Q_INT32 sx = dstRect.x() - x; + Q_INT32 sy = dstRect.y() - y; + Q_INT32 sw = dstRect.width(); + Q_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/krita/plugins/tools/tool_filter/kis_filterop.h b/krita/plugins/tools/tool_filter/kis_filterop.h new file mode 100644 index 00000000..06703b34 --- /dev/null +++ b/krita/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/krita/plugins/tools/tool_filter/kis_tool_filter.cc b/krita/plugins/tools/tool_filter/kis_tool_filter.cc new file mode 100644 index 00000000..1cc1240f --- /dev/null +++ b/krita/plugins/tools/tool_filter/kis_tool_filter.cc @@ -0,0 +1,154 @@ +/* + * kis_tool_filter.cc - part of Krita + * + * 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, + 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) ); +} + +QWidget* KisToolFilter::createOptionWidget(QWidget* parent) +{ + QWidget *widget = super::createOptionWidget(parent); + + m_cbFilter = new KisCmbIDList(widget); + Q_CHECK_PTR(m_cbFilter); + + QLabel* lbFilter = new QLabel(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 QGridLayout(widget, 1, 1, 0, 6); + Q_CHECK_PTR(m_optionLayout); + super::addOptionWidgetLayout(m_optionLayout); + + connect(m_cbFilter, SIGNAL(activated ( const KisID& )), this, 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/krita/plugins/tools/tool_filter/kis_tool_filter.h b/krita/plugins/tools/tool_filter/kis_tool_filter.h new file mode 100644 index 00000000..631c1355 --- /dev/null +++ b/krita/plugins/tools/tool_filter/kis_tool_filter.h @@ -0,0 +1,80 @@ +/* + * kis_tool_filter.h - part of Krita + * + * 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 QComboBox; +class QGridLayout; +class KisEvent; +class KisFilterConfigurationWidget; +class KisButtonPressEvent; +class KisView; +class KisID; +class KisCmbIDList; + + +class KisToolFilter : public KisToolFreehand { + Q_OBJECT + typedef KisToolFreehand super; + +public: + KisToolFilter(); + virtual ~KisToolFilter(); + + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_FREEHAND; } + virtual Q_UINT32 priority() { return 1; } + virtual QWidget* createOptionWidget(QWidget* parent); + +public slots: + void changeFilter( const KisID & filter); + +protected: + virtual void initPaint(KisEvent *e); + +private: + KisFilterSP m_filter; + QWidget* m_filterConfigurationWidget; + QGridLayout* 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/krita/plugins/tools/tool_filter/kritatoolfilter.desktop b/krita/plugins/tools/tool_filter/kritatoolfilter.desktop new file mode 100644 index 00000000..16a4078f --- /dev/null +++ b/krita/plugins/tools/tool_filter/kritatoolfilter.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=Krita/Tool +Type=Service +X-KDE-Library=kritatoolfilter +X-Krita-Version=2 diff --git a/krita/plugins/tools/tool_filter/tool_filter.cc b/krita/plugins/tools/tool_filter/tool_filter.cc new file mode 100644 index 00000000..2102dfdb --- /dev/null +++ b/krita/plugins/tools/tool_filter/tool_filter.cc @@ -0,0 +1,68 @@ +/* + * tool_filter.cc -- Part of Krita + * + * 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( kritatoolfilter, ToolFilterFactory( "krita" ) ) + + +ToolFilter::ToolFilter(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(ToolFilterFactory::instance()); + + if ( parent->inherits("KisToolRegistry") ) + { + KisToolRegistry * r = dynamic_cast(parent); + 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/krita/plugins/tools/tool_filter/tool_filter.h b/krita/plugins/tools/tool_filter/tool_filter.h new file mode 100644 index 00000000..2eee589a --- /dev/null +++ b/krita/plugins/tools/tool_filter/tool_filter.h @@ -0,0 +1,42 @@ +/* + * 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 +public: + ToolFilter(QObject *parent, const char *name, const QStringList &); + virtual ~ToolFilter(); + +private: + + KisView * m_view; + +}; + +#endif // TOOL_FILTER_H_ diff --git a/krita/plugins/tools/tool_filter/tool_filter.png b/krita/plugins/tools/tool_filter/tool_filter.png new file mode 100644 index 00000000..4ec58552 Binary files /dev/null and b/krita/plugins/tools/tool_filter/tool_filter.png differ diff --git a/krita/plugins/tools/tool_filter/tool_filter.svg b/krita/plugins/tools/tool_filter/tool_filter.svg new file mode 100644 index 00000000..44ded846 --- /dev/null +++ b/krita/plugins/tools/tool_filter/tool_filter.svg @@ -0,0 +1,468 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/krita/plugins/tools/tool_filter/tool_filter_cursor.png b/krita/plugins/tools/tool_filter/tool_filter_cursor.png new file mode 100644 index 00000000..da119c77 Binary files /dev/null and b/krita/plugins/tools/tool_filter/tool_filter_cursor.png differ diff --git a/krita/plugins/tools/tool_perspectivegrid/Makefile.am b/krita/plugins/tools/tool_perspectivegrid/Makefile.am new file mode 100644 index 00000000..f6182410 --- /dev/null +++ b/krita/plugins/tools/tool_perspectivegrid/Makefile.am @@ -0,0 +1,34 @@ +kde_services_DATA = kritatoolperspectivegrid.desktop + +# all_includes must remain last! +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kritatoolperspectivegrid_la_SOURCES = \ + tool_perspectivegrid.cc \ + kis_tool_perspectivegrid.cc + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = kritatoolperspectivegrid.la + +noinst_HEADERS = \ + tool_perspectivegrid.h \ + kis_tool_perspectivegrid.h + +kritatoolperspectivegrid_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritatoolperspectivegrid_la_LIBADD = ../../../libkritacommon.la + +METASOURCES = AUTO + +KDE_OPTIONS = nofinal + +kritapics_DATA = \ + tool_perspectivegrid.png + +kritapicsdir = $(kde_datadir)/krita/pics + diff --git a/krita/plugins/tools/tool_perspectivegrid/kis_tool_perspectivegrid.cc b/krita/plugins/tools/tool_perspectivegrid/kis_tool_perspectivegrid.cc new file mode 100644 index 00000000..944807eb --- /dev/null +++ b/krita/plugins/tools/tool_perspectivegrid/kis_tool_perspectivegrid.cc @@ -0,0 +1,499 @@ +/* + * kis_tool_perspectivegrid.cc - part of Krita + * + * 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 QPoint& mousep, const QPoint point) +{ + return (QRect( (point.x() - m_handleHalfSize), (point.y() - m_handleHalfSize), m_handleSize, m_handleSize).contains(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() == 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() == LeftButton){ + // Look for the handle which was pressed + if (!m_subject) + return; + KisCanvasController *controller = m_subject->canvasController(); + Q_ASSERT(controller); + QPoint mousep = controller->windowToView( event->pos().roundQPoint() ); + + for( QValueList::const_iterator it = pGrid->begin(); it != pGrid->end(); ++it) + { + KisSubPerspectiveGrid* grid = *it; + if( mouseNear( mousep, controller->windowToView(grid->topLeft()->roundQPoint() ) ) ) + { + kdDebug() << " PRESS TOPLEFT HANDLE " << endl; + m_mode = MODE_DRAGING_NODE; + m_selectedNode1 = grid->topLeft(); + break; + } + else if( mouseNear( mousep, controller->windowToView(grid->topRight()->roundQPoint() ) ) ) + { + kdDebug() << " PRESS TOPRIGHT HANDLE " << endl; + m_mode = MODE_DRAGING_NODE; + m_selectedNode1 = grid->topRight(); + break; + } + else if( mouseNear( mousep, controller->windowToView(grid->bottomLeft()->roundQPoint() ) ) ) + { + kdDebug() << " PRESS BOTTOMLEFT HANDLE " << endl; + m_mode = MODE_DRAGING_NODE; + m_selectedNode1 = grid->bottomLeft(); + break; + } + else if( mouseNear( mousep, controller->windowToView(grid->bottomRight()->roundQPoint() ) ) ) + { + 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) ).roundQPoint() ) ) + { + 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) ).roundQPoint() ) ) + { + 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) ).roundQPoint() ) ) + { + 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) ).roundQPoint() ) ) + { + 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() == 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 QRect&) +{ + 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; + + QPen pen(Qt::white); + + gc.setPen(pen); + gc.setRasterOp(Qt::XorROP); + + KisCanvasController *controller = m_subject->canvasController(); + KisPoint start, end; + QPoint startPos; + QPoint endPos; + + if (m_dragging) { + startPos = controller->windowToView(m_dragStart.floorQPoint()); + endPos = controller->windowToView(m_dragEnd.floorQPoint()); + 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.floorQPoint()); + endPos = controller->windowToView(end.floorQPoint()); + + gc.drawLine(startPos, endPos); + + start = end; + } + } + } +} + +void KisToolPerspectiveGrid::drawSmallRectangle(KisCanvasPainter& gc, QPoint 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(); + + QPen pen(Qt::white); + QPoint startPos; + QPoint endPos; + + gc.setPen(pen); + gc.setRasterOp(Qt::XorROP); + KisPerspectiveGrid* pGrid = m_subject->currentImg()->perspectiveGrid(); + + for( QValueList::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()->roundQPoint()); + endPos = controller->windowToView(grid->topRight()->roundQPoint()); + 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()->roundQPoint()); + endPos = controller->windowToView(grid->bottomRight()->roundQPoint()); + gc.drawLine( startPos, endPos ); + if( !grid->rightGrid() ) + { + drawSmallRectangle(gc, (endPos + startPos) / 2); + } + } + if(drawBottom) { + startPos = controller->windowToView(grid->bottomRight()->roundQPoint()); + endPos = controller->windowToView(grid->bottomLeft()->roundQPoint()); + 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()->roundQPoint()); + endPos = controller->windowToView(grid->topLeft()->roundQPoint()); + 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.) + { + QPoint tbVp = controller->windowToView(tbVpf.roundQPoint()); + 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 + QPoint lrVp = controller->windowToView(lrVpf.roundQPoint()); + 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, + SLOT(activate()), + collection, + name()); + Q_CHECK_PTR(m_action); + m_action->setExclusiveGroup("tools"); + m_action->setToolTip(i18n("Edit the perspective grid")); + m_ownAction = true; + } +} + + +// QWidget* KisToolPerspectiveGrid::createOptionWidget(QWidget* parent) +// { +// return 0; +// } +// +// QWidget* KisToolPerspectiveGrid::optionWidget() +// { +// return 0; +// } + + +#include "kis_tool_perspectivegrid.moc" diff --git a/krita/plugins/tools/tool_perspectivegrid/kis_tool_perspectivegrid.h b/krita/plugins/tools/tool_perspectivegrid/kis_tool_perspectivegrid.h new file mode 100644 index 00000000..b6318c7d --- /dev/null +++ b/krita/plugins/tools/tool_perspectivegrid/kis_tool_perspectivegrid.h @@ -0,0 +1,110 @@ +/* + * kis_tool_perspectivegrid.h - part of Krita + * + * 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 + 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 Q_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); + +// QWidget* createOptionWidget(QWidget* parent); +// virtual QWidget* optionWidget(); + +public slots: + virtual void activate(); + void deactivate(); + +protected: + virtual void paint(KisCanvasPainter& gc); + virtual void paint(KisCanvasPainter& gc, const QRect& rc); + void drawGridCreation(KisCanvasPainter& gc); + void drawGridCreation(); + void drawGrid(KisCanvasPainter& gc); + void drawGrid(); + +private: + void drawSmallRectangle(KisCanvasPainter& gc, QPoint p); + bool mouseNear(const QPoint& mousep, const QPoint point); + +protected: + KisPoint m_dragStart; + KisPoint m_dragEnd; + + bool m_dragging; +private: + typedef QValueVector KisPointVector; + KisCanvasSubject *m_subject; + KisPointVector m_points; + PerspectiveGridEditionMode m_mode; + Q_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/krita/plugins/tools/tool_perspectivegrid/kritatoolperspectivegrid.desktop b/krita/plugins/tools/tool_perspectivegrid/kritatoolperspectivegrid.desktop new file mode 100644 index 00000000..ec9c0dea --- /dev/null +++ b/krita/plugins/tools/tool_perspectivegrid/kritatoolperspectivegrid.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=Krita/Tool +Type=Service +X-KDE-Library=kritatoolperspectivegrid +X-Krita-Version=2 diff --git a/krita/plugins/tools/tool_perspectivegrid/tool_perspectivegrid.cc b/krita/plugins/tools/tool_perspectivegrid/tool_perspectivegrid.cc new file mode 100644 index 00000000..157a7457 --- /dev/null +++ b/krita/plugins/tools/tool_perspectivegrid/tool_perspectivegrid.cc @@ -0,0 +1,62 @@ +/* + * tool_perspectivegrid.cc -- Part of Krita + * + * 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( kritatoolperspectivegrid, ToolPerspectiveGridFactory( "krita" ) ) + + +ToolPerspectiveGrid::ToolPerspectiveGrid(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(ToolPerspectiveGridFactory::instance()); + + if ( parent->inherits("KisToolRegistry") ) + { + KisToolRegistry * r = dynamic_cast(parent); + r->add(new KisToolPerspectiveGridFactory()); + } + +} + +ToolPerspectiveGrid::~ToolPerspectiveGrid() +{ +} + +#include "tool_perspectivegrid.moc" diff --git a/krita/plugins/tools/tool_perspectivegrid/tool_perspectivegrid.h b/krita/plugins/tools/tool_perspectivegrid/tool_perspectivegrid.h new file mode 100644 index 00000000..e98cbf09 --- /dev/null +++ b/krita/plugins/tools/tool_perspectivegrid/tool_perspectivegrid.h @@ -0,0 +1,42 @@ +/* + * 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 +public: + ToolPerspectiveGrid(QObject *parent, const char *name, const QStringList &); + virtual ~ToolPerspectiveGrid(); + +private: + + KisView * m_view; + +}; + +#endif // TOOL_PERSPECTIVE_GRID_H_ diff --git a/krita/plugins/tools/tool_perspectivegrid/tool_perspectivegrid.png b/krita/plugins/tools/tool_perspectivegrid/tool_perspectivegrid.png new file mode 100644 index 00000000..3948131d Binary files /dev/null and b/krita/plugins/tools/tool_perspectivegrid/tool_perspectivegrid.png differ diff --git a/krita/plugins/tools/tool_perspectivegrid/tool_perspectivegrid.svg b/krita/plugins/tools/tool_perspectivegrid/tool_perspectivegrid.svg new file mode 100644 index 00000000..24405305 --- /dev/null +++ b/krita/plugins/tools/tool_perspectivegrid/tool_perspectivegrid.svg @@ -0,0 +1,87 @@ + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/krita/plugins/tools/tool_perspectivetransform/Makefile.am b/krita/plugins/tools/tool_perspectivetransform/Makefile.am new file mode 100644 index 00000000..5a833521 --- /dev/null +++ b/krita/plugins/tools/tool_perspectivetransform/Makefile.am @@ -0,0 +1,34 @@ +kde_services_DATA = kritatoolperspectivetransform.desktop + +# all_includes must remain last! +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kritatoolperspectivetransform_la_SOURCES = \ + tool_perspectivetransform.cc \ + kis_tool_perspectivetransform.cc + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = kritatoolperspectivetransform.la + +noinst_HEADERS = \ + tool_perspectivetransform.h \ + kis_tool_perspectivetransform.h + +kritatoolperspectivetransform_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritatoolperspectivetransform_la_LIBADD = ../../../libkritacommon.la + +kritatoolperspectivetransform_la_METASOURCES = AUTO + +KDE_OPTIONS = nofinal + +kritapics_DATA = \ + tool_perspectivetransform.png + +kritapicsdir = $(kde_datadir)/krita/pics + diff --git a/krita/plugins/tools/tool_perspectivetransform/kis_tool_perspectivetransform.cc b/krita/plugins/tools/tool_perspectivetransform/kis_tool_perspectivetransform.cc new file mode 100644 index 00000000..f334c429 --- /dev/null +++ b/krita/plugins/tools/tool_perspectivetransform/kis_tool_perspectivetransform.cc @@ -0,0 +1,742 @@ +/* + * kis_tool_transform.cc -- part of Krita + * + * 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, QRect initialRect); + virtual ~PerspectiveTransformCmd(); + + public: + virtual void execute(); + virtual void unexecute(); + void transformArgs(KisPoint &topleft, KisPoint &topright, KisPoint &bottomleft, KisPoint& bottomright) const; + KisSelectionSP origSelection(QRect& initialRect) const; + KisPaintDeviceSP theDevice(); + KisPaintDeviceSP origDevice(); + + private: + QRect 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, QRect 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(QRect& 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(), SIGNAL(sigLayerActivated(KisLayerSP)), this, 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(), SIGNAL(sigLayerActivated(KisLayerSP)), this, SLOT(slotLayerActivated(KisLayerSP))); +} + +void KisToolPerspectiveTransform::initHandles() +{ +// Q_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 = m_initialRect.topLeft(); + m_topright = m_initialRect.topRight(); + m_bottomleft = m_initialRect.bottomLeft(); + m_bottomright = m_initialRect.bottomRight(); + + m_subject->canvasController() ->updateCanvas(); +} + +void KisToolPerspectiveTransform::paint(KisCanvasPainter& gc) +{ + paintOutline(gc, QRect()); +} + +void KisToolPerspectiveTransform::paint(KisCanvasPainter& gc, const QRect& rc) +{ + paintOutline(gc, rc); +} + +bool KisToolPerspectiveTransform::mouseNear(const QPoint& mousep, const QPoint point) +{ + return (QRect( (point.x() - m_handleHalfSize), (point.y() - m_handleHalfSize), m_handleSize, m_handleSize).contains(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() == LeftButton) { + m_actualyMoveWhileSelected = false; + m_dragEnd = event->pos(); + KisCanvasController *controller = m_subject->canvasController(); + QPoint mousep = controller->windowToView( event->pos().roundQPoint() ); + if( mouseNear( mousep, controller->windowToView(m_topleft.roundQPoint() ) ) ) + { + kdDebug() << " PRESS TOPLEFT HANDLE " << endl; + m_currentSelectedPoint = &m_topleft; + } + else if( mouseNear( mousep, controller->windowToView(m_topright.roundQPoint() ) ) ) + { + kdDebug() << " PRESS TOPRIGHT HANDLE " << endl; + m_currentSelectedPoint = &m_topright; + } + else if( mouseNear( mousep, controller->windowToView(m_bottomleft.roundQPoint() ) ) ) + { + kdDebug() << " PRESS BOTTOMLEFT HANDLE " << endl; + m_currentSelectedPoint = &m_bottomleft; + } + else if( mouseNear( mousep, controller->windowToView(m_bottomright.roundQPoint() ) ) ) + { + kdDebug() << " PRESS BOTTOMRIGHT HANDLE " << endl; + m_currentSelectedPoint = &m_bottomright; + } else if( mouseNear( mousep, controller->windowToView(KisPoint((m_topleft+m_topright)*0.5).roundQPoint() ) ) ) + { + kdDebug() << " PRESS TOP HANDLE " << endl; + m_handleSelected = TOPHANDLE; + }else if( mouseNear( mousep, controller->windowToView(KisPoint((m_topleft+m_bottomleft)*0.5).roundQPoint() ) ) ) + { + kdDebug() << " PRESS LEFT HANDLE " << endl; + m_handleSelected = LEFTHANDLE; + }else if( mouseNear( mousep, controller->windowToView(KisPoint((m_bottomleft+m_bottomright)*0.5).roundQPoint() ) ) ) + { + kdDebug() << " PRESS BOTTOM HANDLE " << endl; + m_handleSelected = BOTTOMHANDLE; + }else if( mouseNear( mousep, controller->windowToView(KisPoint((m_bottomright+m_topright)*0.5).roundQPoint() ) ) ) + { + 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).roundQPoint() ) ) ) + { + 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, m_initialRect.topLeft() ); + KisPoint topRight = KisPerspectiveMath::matProd(matrixFrom, m_initialRect.topRight() ); + KisPoint bottomLeft = KisPerspectiveMath::matProd(matrixFrom, m_initialRect.bottomLeft() ); + KisPoint bottomRight = KisPerspectiveMath::matProd(matrixFrom, m_initialRect.bottomRight() ); + QRect 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, m_initialRect.topLeft()); + m_topright = KisPerspectiveMath::matProd(matrixTo, m_initialRect.topRight()); + m_bottomleft = KisPerspectiveMath::matProd(matrixTo, m_initialRect.bottomLeft()); + m_bottomright = KisPerspectiveMath::matProd(matrixTo, 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() == LeftButton) + { + switch(m_interractionMode) + { + case DRAWRECTINTERRACTION: + { + if (m_dragging && event->button() == 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, m_initialRect.topLeft()); + m_topright = KisPerspectiveMath::matProd(matrix, m_initialRect.topRight()); + m_bottomleft = KisPerspectiveMath::matProd(matrix, m_initialRect.bottomLeft()); + m_bottomright = KisPerspectiveMath::matProd(matrix, m_initialRect.bottomRight()); + m_interractionMode = EDITRECTINTERRACTION; + paintOutline(); + QApplication::setOverrideCursor(KisCursor::waitCursor()); + transform(); + QApplication::restoreOverrideCursor(); + } else { + paintOutline(); + } + } + } + break; + case EDITRECTINTERRACTION: + { + if(m_currentSelectedPoint ) + { + m_currentSelectedPoint = 0; + if(m_actualyMoveWhileSelected) + { + paintOutline(); + QApplication::setOverrideCursor(KisCursor::waitCursor()); + transform(); + QApplication::restoreOverrideCursor(); + } + } + if(m_handleSelected != NOHANDLE) + { + m_handleSelected = NOHANDLE; + if(m_actualyMoveWhileSelected) + { +// paintOutline(); + QApplication::setOverrideCursor(KisCursor::waitCursor()); + transform(); + QApplication::restoreOverrideCursor(); + } + } + } + break; + } + } +} + +void KisToolPerspectiveTransform::paintOutline() +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + KisCanvas *canvas = controller->kiscanvas(); + KisCanvasPainter gc(canvas); + QRect rc; + + paintOutline(gc, rc); + } +} + +void KisToolPerspectiveTransform::paintOutline(KisCanvasPainter& gc, const QRect&) +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + RasterOp op = gc.rasterOp(); + QPen old = gc.pen(); + QPen pen(Qt::SolidLine); + pen.setWidth(1); + Q_ASSERT(controller); + + switch(m_interractionMode) + { + case DRAWRECTINTERRACTION: + { + kdDebug() << "DRAWRECTINTERRACTION paintOutline " << m_points.size() << endl; + KisPoint start, end; + QPoint startPos; + QPoint 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.floorQPoint()); + endPos = controller->windowToView(end.floorQPoint()); + + gc.drawLine(startPos, endPos); + + start = end; + } + } + } + break; + case EDITRECTINTERRACTION: + { + QPoint topleft = controller->windowToView(m_topleft ).roundQPoint(); + QPoint topright = controller->windowToView(m_topright).roundQPoint(); + QPoint bottomleft = controller->windowToView(m_bottomleft).roundQPoint(); + QPoint bottomright = controller->windowToView(m_bottomright).roundQPoint(); + + gc.setRasterOp(Qt::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. + QRect 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) + { + QRect 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(); +} + + +QWidget* KisToolPerspectiveTransform::createOptionWidget(QWidget* /*parent*/) +{ +#if 0 + m_optWidget = new WdgToolPerspectiveTransform(parent); + 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, SIGNAL(activated(const KisID &)), + this, SLOT(slotSetFilter(const KisID &))); + + KisID filterID = m_optWidget->cmbFilter->currentItem(); + m_filter = KisFilterStrategyRegistry::instance()->get(filterID); + +/* + connect(m_optWidget->intStartX, SIGNAL(valueChanged(int)), this, SLOT(setStartX(int))); + connect(m_optWidget->intStartY, SIGNAL(valueChanged(int)), this, SLOT(setStartY(int))); + connect(m_optWidget->intEndX, SIGNAL(valueChanged(int)), this, SLOT(setEndX(int))); + connect(m_optWidget->intEndY, SIGNAL(valueChanged(int)), this, 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; +} + +QWidget* 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, + 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/krita/plugins/tools/tool_perspectivetransform/kis_tool_perspectivetransform.h b/krita/plugins/tools/tool_perspectivetransform/kis_tool_perspectivetransform.h new file mode 100644 index 00000000..e2600cfc --- /dev/null +++ b/krita/plugins/tools/tool_perspectivetransform/kis_tool_perspectivetransform.h @@ -0,0 +1,130 @@ +/* + * kis_tool_transform.h - part of Krita + * + * 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 + enum InterractionMode { DRAWRECTINTERRACTION, EDITRECTINTERRACTION }; + enum HandleSelected { NOHANDLE, TOPHANDLE, BOTTOMHANDLE, RIGHTHANDLE, LEFTHANDLE, MIDDLEHANDLE }; +public: + KisToolPerspectiveTransform(); + virtual ~KisToolPerspectiveTransform(); + + virtual QWidget* createOptionWidget(QWidget* parent); + virtual QWidget* optionWidget(); + + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_TRANSFORM; } + virtual Q_UINT32 priority() { return 4; } + virtual void paint(KisCanvasPainter& gc); + virtual void paint(KisCanvasPainter& gc, const QRect& 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 QPoint& mousep, const QPoint point); + void paintOutline(KisCanvasPainter& gc, const QRect& rc); + void transform(); + void initHandles(); + +private slots: + void slotLayerActivated(KisLayerSP); + +protected slots: + virtual void activate(); + +private: + bool m_dragging; + InterractionMode m_interractionMode; + QRect 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 QValueVector 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/krita/plugins/tools/tool_perspectivetransform/kritatoolperspectivetransform.desktop b/krita/plugins/tools/tool_perspectivetransform/kritatoolperspectivetransform.desktop new file mode 100644 index 00000000..4ad0c64f --- /dev/null +++ b/krita/plugins/tools/tool_perspectivetransform/kritatoolperspectivetransform.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=Krita/Tool +Type=Service +X-KDE-Library=kritatoolperspectivetransform +X-Krita-Version=2 diff --git a/krita/plugins/tools/tool_perspectivetransform/tool_perspectivetransform.cc b/krita/plugins/tools/tool_perspectivetransform/tool_perspectivetransform.cc new file mode 100644 index 00000000..3fdbe3bb --- /dev/null +++ b/krita/plugins/tools/tool_perspectivetransform/tool_perspectivetransform.cc @@ -0,0 +1,63 @@ +/* + * tool_perspectivetransform.cc -- Part of Krita + * + * 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( kritatoolperspectivetransform, ToolPerspectiveTransformFactory( "krita" ) ) + + +ToolPerspectiveTransform::ToolPerspectiveTransform(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(ToolPerspectiveTransformFactory::instance()); + + if ( parent->inherits("KisToolRegistry") ) + { + kdDebug() << " add perspective transform tool to the registry" << endl; + KisToolRegistry * r = dynamic_cast(parent); + r->add(new KisToolPerspectiveTransformFactory()); + } + +} + +ToolPerspectiveTransform::~ToolPerspectiveTransform() +{ +} + +#include "tool_perspectivetransform.moc" diff --git a/krita/plugins/tools/tool_perspectivetransform/tool_perspectivetransform.h b/krita/plugins/tools/tool_perspectivetransform/tool_perspectivetransform.h new file mode 100644 index 00000000..6cc6370f --- /dev/null +++ b/krita/plugins/tools/tool_perspectivetransform/tool_perspectivetransform.h @@ -0,0 +1,42 @@ +/* + * 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 +public: + ToolPerspectiveTransform(QObject *parent, const char *name, const QStringList &); + virtual ~ToolPerspectiveTransform(); + +private: + + KisView * m_view; + +}; + +#endif // TOOL_PERSPECTIVE_TRANSFORM_H_ diff --git a/krita/plugins/tools/tool_perspectivetransform/tool_perspectivetransform.png b/krita/plugins/tools/tool_perspectivetransform/tool_perspectivetransform.png new file mode 100644 index 00000000..7b6fea09 Binary files /dev/null and b/krita/plugins/tools/tool_perspectivetransform/tool_perspectivetransform.png differ diff --git a/krita/plugins/tools/tool_perspectivetransform/tool_perspectivetransform.svg b/krita/plugins/tools/tool_perspectivetransform/tool_perspectivetransform.svg new file mode 100644 index 00000000..24405305 --- /dev/null +++ b/krita/plugins/tools/tool_perspectivetransform/tool_perspectivetransform.svg @@ -0,0 +1,87 @@ + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/krita/plugins/tools/tool_polygon/Makefile.am b/krita/plugins/tools/tool_polygon/Makefile.am new file mode 100644 index 00000000..dec22b37 --- /dev/null +++ b/krita/plugins/tools/tool_polygon/Makefile.am @@ -0,0 +1,35 @@ +kde_services_DATA = kritatoolpolygon.desktop + +# all_includes must remain last! +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kritatoolpolygon_la_SOURCES = \ + tool_polygon.cc \ + kis_tool_polygon.cc + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = kritatoolpolygon.la + +noinst_HEADERS = \ + tool_polygon.h \ + kis_tool_polygon.h + +kritatoolpolygon_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritatoolpolygon_la_LIBADD = ../../../libkritacommon.la + +kritatoolpolygon_la_METASOURCES = AUTO + +KDE_OPTIONS = nofinal + +kritapics_DATA = \ + tool_polygon_cursor.png \ + tool_polygon.png + +kritapicsdir = $(kde_datadir)/krita/pics + diff --git a/krita/plugins/tools/tool_polygon/kis_tool_polygon.cc b/krita/plugins/tools/tool_polygon/kis_tool_polygon.cc new file mode 100644 index 00000000..9589e19f --- /dev/null +++ b/krita/plugins/tools/tool_polygon/kis_tool_polygon.cc @@ -0,0 +1,252 @@ +/* + * kis_tool_polygon.cc -- part of Krita + * + * 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() == 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() == 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() == LeftButton) { + m_dragging = false; + m_points.append (m_dragEnd); + } + + if (m_dragging && event->button() == RightButton) { + + } +} + +void KisToolPolygon::paint(KisCanvasPainter& gc) +{ + draw(gc); +} + +void KisToolPolygon::paint(KisCanvasPainter& gc, const QRect&) +{ + 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; + + QPen pen(Qt::white, 0, Qt::SolidLine); + + gc.setPen(pen); + gc.setRasterOp(Qt::XorROP); + + KisCanvasController *controller = m_subject->canvasController(); + KisPoint start, end; + QPoint startPos; + QPoint endPos; + + if (m_dragging) { + startPos = controller->windowToView(m_dragStart.floorQPoint()); + endPos = controller->windowToView(m_dragEnd.floorQPoint()); + 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.floorQPoint()); + endPos = controller->windowToView(end.floorQPoint()); + + gc.drawLine(startPos, endPos); + + start = end; + } + } + } +} + + + +void KisToolPolygon::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + KShortcut shortcut(Qt::Key_Plus); + shortcut.append(KShortcut(Qt::Key_F9)); + m_action = new KRadioAction(i18n("&Polygon"), + "tool_polygon", + shortcut, + this, + 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(QKeyEvent *e) +{ + if (e->key()==Qt::Key_Escape) { + // erase old lines on canvas + draw(); + m_dragging = false; + m_points.clear(); + } +} + + +#include "kis_tool_polygon.moc" diff --git a/krita/plugins/tools/tool_polygon/kis_tool_polygon.h b/krita/plugins/tools/tool_polygon/kis_tool_polygon.h new file mode 100644 index 00000000..7ca24914 --- /dev/null +++ b/krita/plugins/tools/tool_polygon/kis_tool_polygon.h @@ -0,0 +1,101 @@ +/* + * kis_tool_polygon.h - part of Krita + * + * 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 + +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 Q_UINT32 priority() { return 4; } + virtual void buttonPress(KisButtonPressEvent *event); + virtual void move(KisMoveEvent *event); + virtual void buttonRelease(KisButtonReleaseEvent *event); + virtual QString 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 QRect& rc); + void draw(KisCanvasPainter& gc); + void draw(); + void finish(); + virtual void keyPress(QKeyEvent *e); +protected: + KisPoint m_dragStart; + KisPoint m_dragEnd; + + bool m_dragging; + KisImageSP m_currentImage; +private: + typedef QValueVector 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/krita/plugins/tools/tool_polygon/kritatoolpolygon.desktop b/krita/plugins/tools/tool_polygon/kritatoolpolygon.desktop new file mode 100644 index 00000000..08d8b162 --- /dev/null +++ b/krita/plugins/tools/tool_polygon/kritatoolpolygon.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=Krita/Tool +Type=Service +X-KDE-Library=kritatoolpolygon +X-Krita-Version=2 diff --git a/krita/plugins/tools/tool_polygon/tool_polygon.cc b/krita/plugins/tools/tool_polygon/tool_polygon.cc new file mode 100644 index 00000000..a1fec49c --- /dev/null +++ b/krita/plugins/tools/tool_polygon/tool_polygon.cc @@ -0,0 +1,62 @@ +/* + * tool_polygon.cc -- Part of Krita + * + * 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( kritatoolpolygon, ToolPolygonFactory( "krita" ) ) + + +ToolPolygon::ToolPolygon(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(ToolPolygonFactory::instance()); + + if ( parent->inherits("KisToolRegistry") ) + { + KisToolRegistry * r = dynamic_cast( parent ); + r->add(new KisToolPolygonFactory()); + } + +} + +ToolPolygon::~ToolPolygon() +{ +} + +//#include "tool_polygon.moc" diff --git a/krita/plugins/tools/tool_polygon/tool_polygon.h b/krita/plugins/tools/tool_polygon/tool_polygon.h new file mode 100644 index 00000000..6249d935 --- /dev/null +++ b/krita/plugins/tools/tool_polygon/tool_polygon.h @@ -0,0 +1,38 @@ +/* + * 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 + +public: + + ToolPolygon(QObject *parent, const char *name, const QStringList &); + virtual ~ToolPolygon(); + +}; + +#endif // TOOL_POLYGON_H_ diff --git a/krita/plugins/tools/tool_polygon/tool_polygon.png b/krita/plugins/tools/tool_polygon/tool_polygon.png new file mode 100644 index 00000000..0f1627d9 Binary files /dev/null and b/krita/plugins/tools/tool_polygon/tool_polygon.png differ diff --git a/krita/plugins/tools/tool_polygon/tool_polygon_cursor.png b/krita/plugins/tools/tool_polygon/tool_polygon_cursor.png new file mode 100644 index 00000000..4d312ade Binary files /dev/null and b/krita/plugins/tools/tool_polygon/tool_polygon_cursor.png differ diff --git a/krita/plugins/tools/tool_polyline/Makefile.am b/krita/plugins/tools/tool_polyline/Makefile.am new file mode 100644 index 00000000..298119b5 --- /dev/null +++ b/krita/plugins/tools/tool_polyline/Makefile.am @@ -0,0 +1,35 @@ +kde_services_DATA = kritatoolpolyline.desktop + +# all_includes must remain last! +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kritatoolpolyline_la_SOURCES = \ + tool_polyline.cc \ + kis_tool_polyline.cc + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = kritatoolpolyline.la + +noinst_HEADERS = \ + tool_polyline.h \ + kis_tool_polyline.h + +kritatoolpolyline_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritatoolpolyline_la_LIBADD = ../../../libkritacommon.la + +kritatoolpolyline_la_METASOURCES = AUTO + +KDE_OPTIONS = nofinal + +kritapics_DATA = \ + tool_polyline_cursor.png \ + polyline.png + +kritapicsdir = $(kde_datadir)/krita/pics + diff --git a/krita/plugins/tools/tool_polyline/kis_tool_polyline.cc b/krita/plugins/tools/tool_polyline/kis_tool_polyline.cc new file mode 100644 index 00000000..2f7a8e59 --- /dev/null +++ b/krita/plugins/tools/tool_polyline/kis_tool_polyline.cc @@ -0,0 +1,271 @@ +/* + * kis_tool_polyline.cc -- part of Krita + * + * 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() == LeftButton && event->state() != Qt::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() == LeftButton && event->state() == Qt::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() == LeftButton) { + m_dragging = false; + m_points.append (m_dragEnd); + } + + if (m_dragging && event->button() == RightButton) { + + } +} + + +void KisToolPolyline::doubleClick(KisDoubleClickEvent *) +{ + finish(); +} + + +void KisToolPolyline::paint(KisCanvasPainter& gc) +{ + draw(gc); +} + +void KisToolPolyline::paint(KisCanvasPainter& gc, const QRect&) +{ + 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; + + QPen pen(Qt::white, 0, Qt::SolidLine); + + gc.setPen(pen); + gc.setRasterOp(Qt::XorROP); + + KisCanvasController *controller = m_subject->canvasController(); + KisPoint start, end; + QPoint startPos; + QPoint endPos; + + if (m_dragging) { + startPos = controller->windowToView(m_dragStart.floorQPoint()); + endPos = controller->windowToView(m_dragEnd.floorQPoint()); + 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.floorQPoint()); + endPos = controller->windowToView(end.floorQPoint()); + + gc.drawLine(startPos, endPos); + + start = end; + } + } + } +} + +void KisToolPolyline::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + KShortcut shortcut(Qt::Key_Plus); + shortcut.append(KShortcut(Qt::Key_F9)); + m_action = new KRadioAction(i18n("&Polyline"), + "polyline", + shortcut, + this, + 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; + } +} + +QString KisToolPolyline::quickHelp() const +{ + return i18n("Press shift-mouseclick to end the polyline."); +} + +void KisToolPolyline::keyPress(QKeyEvent *e) +{ + if (e->key()==Qt::Key_Escape) { + // erase old lines on canvas + draw(); + m_dragging = false; + m_points.clear(); + } +} + +#include "kis_tool_polyline.moc" diff --git a/krita/plugins/tools/tool_polyline/kis_tool_polyline.h b/krita/plugins/tools/tool_polyline/kis_tool_polyline.h new file mode 100644 index 00000000..5dfff695 --- /dev/null +++ b/krita/plugins/tools/tool_polyline/kis_tool_polyline.h @@ -0,0 +1,108 @@ +/* + * kis_tool_polyline.h - part of Krita + * + * 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 + +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 Q_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 QString quickHelp() const; + void finish(); + virtual void keyPress(QKeyEvent *e); + +public slots: + + void deactivate(); + +protected: + virtual void paint(KisCanvasPainter& gc); + virtual void paint(KisCanvasPainter& gc, const QRect& rc); + void draw(KisCanvasPainter& gc); + void draw(); + +protected: + KisPoint m_dragStart; + KisPoint m_dragEnd; + + bool m_dragging; + KisImageSP m_currentImage; +private: + typedef QValueVector 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/krita/plugins/tools/tool_polyline/kritatoolpolyline.desktop b/krita/plugins/tools/tool_polyline/kritatoolpolyline.desktop new file mode 100644 index 00000000..fc0db01c --- /dev/null +++ b/krita/plugins/tools/tool_polyline/kritatoolpolyline.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=Krita/Tool +Type=Service +X-KDE-Library=kritatoolpolyline +X-Krita-Version=2 diff --git a/krita/plugins/tools/tool_polyline/polyline.png b/krita/plugins/tools/tool_polyline/polyline.png new file mode 100644 index 00000000..d30680da Binary files /dev/null and b/krita/plugins/tools/tool_polyline/polyline.png differ diff --git a/krita/plugins/tools/tool_polyline/tool_polyline.cc b/krita/plugins/tools/tool_polyline/tool_polyline.cc new file mode 100644 index 00000000..ae1fdda5 --- /dev/null +++ b/krita/plugins/tools/tool_polyline/tool_polyline.cc @@ -0,0 +1,64 @@ +/* + * tool_polyline.cc -- Part of Krita + * + * 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( kritatoolpolyline, ToolPolylineFactory( "krita" ) ) + + +ToolPolyline::ToolPolyline(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(ToolPolylineFactory::instance()); + + if ( parent->inherits("KisToolRegistry") ) + { + KisToolRegistry * r = dynamic_cast(parent); + + r->add(new KisToolPolylineFactory()); + } + +} + +ToolPolyline::~ToolPolyline() +{ +} + +#include "tool_polyline.moc" diff --git a/krita/plugins/tools/tool_polyline/tool_polyline.h b/krita/plugins/tools/tool_polyline/tool_polyline.h new file mode 100644 index 00000000..14987487 --- /dev/null +++ b/krita/plugins/tools/tool_polyline/tool_polyline.h @@ -0,0 +1,42 @@ +/* + * 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 +public: + ToolPolyline(QObject *parent, const char *name, const QStringList &); + virtual ~ToolPolyline(); + +private: + + KisView * m_view; + +}; + +#endif // TOOL_POLYLINE_H_ diff --git a/krita/plugins/tools/tool_polyline/tool_polyline_cursor.png b/krita/plugins/tools/tool_polyline/tool_polyline_cursor.png new file mode 100644 index 00000000..54606bce Binary files /dev/null and b/krita/plugins/tools/tool_polyline/tool_polyline_cursor.png differ diff --git a/krita/plugins/tools/tool_selectsimilar/Makefile.am b/krita/plugins/tools/tool_selectsimilar/Makefile.am new file mode 100644 index 00000000..d92642c1 --- /dev/null +++ b/krita/plugins/tools/tool_selectsimilar/Makefile.am @@ -0,0 +1,31 @@ +kde_services_DATA = kritatoolselectsimilar.desktop + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + + +kritatoolselectsimilar_la_SOURCES = selectsimilar.cc kis_tool_selectsimilar.cc +noinst_HEADERS = selectsimilar.h kis_tool_selectsimilar.h + +kde_module_LTLIBRARIES = kritatoolselectsimilar.la + +kritatoolselectsimilar_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritatoolselectsimilar_la_LIBADD = ../../../libkritacommon.la + +kritatoolselectsimilar_la_METASOURCES = AUTO + +KDE_OPTIONS = nofinal + +# directory for pixmaps +kritapics_DATA = \ + tool_similar_selection.png \ + tool_similar_selection_plus_cursor.png \ + tool_similar_selection_minus_cursor.png + +kritapicsdir = $(kde_datadir)/krita/pics + diff --git a/krita/plugins/tools/tool_selectsimilar/kis_tool_selectsimilar.cc b/krita/plugins/tools/tool_selectsimilar/kis_tool_selectsimilar.cc new file mode 100644 index 00000000..cdb38cb3 --- /dev/null +++ b/krita/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 Q_UINT8 * c, int fuzziness, enumSelectionMode mode) +{ + // XXX: Multithread this! + Q_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()); + + Q_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 QTimer(this); + connect(m_timer, SIGNAL(timeout()), 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) { + QApplication::setOverrideCursor(KisCursor::waitCursor()); + KisImageSP img; + KisPaintDeviceSP dev; + QPoint pos; + Q_UINT8 opacity = OPACITY_OPAQUE; + + if (e->button() != QMouseEvent::LeftButton && e->button() != QMouseEvent::RightButton) + return; + + if (!(img = m_subject->currentImg())) + return; + + dev = img->activeDevice(); + + if (!dev || !img->activeLayer()->visible()) + return; + + pos = QPoint(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(); + + QApplication::restoreOverrideCursor(); + } +} + +void KisToolSelectSimilar::slotTimer() +{ +#if KDE_IS_VERSION(3,4,0) + int state = kapp->keyboardMouseState() & (Qt::ShiftButton|Qt::ControlButton|Qt::AltButton); +#else + int state = kapp->keyboardModifiers() & (KApplication::ShiftModifier + |KApplication::ControlModifier|KApplication::Modifier1); +#endif + enumSelectionMode action; + + if (state == Qt::ShiftButton) + action = SELECTION_ADD; + else if (state == Qt::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, 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; +} + +QWidget* KisToolSelectSimilar::createOptionWidget(QWidget* parent) +{ + m_optWidget = new QWidget(parent); + Q_CHECK_PTR(m_optWidget); + + m_optWidget->setCaption(i18n("Similar Selection")); + + QVBoxLayout * l = new QVBoxLayout(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, SIGNAL(actionChanged(int)), this, SLOT(slotSetAction(int))); + + QHBoxLayout * hbox = new QHBoxLayout(l); + Q_CHECK_PTR(hbox); + + QLabel * lbl = new QLabel(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, SIGNAL(valueChanged(int)), this, SLOT(slotSetFuzziness(int))); + + l->addItem(new QSpacerItem(1, 1, QSizePolicy::Fixed, QSizePolicy::Expanding)); + + return m_optWidget; +} + +QWidget* KisToolSelectSimilar::optionWidget() +{ + return m_optWidget; +} + +#include "kis_tool_selectsimilar.moc" diff --git a/krita/plugins/tools/tool_selectsimilar/kis_tool_selectsimilar.h b/krita/plugins/tools/tool_selectsimilar/kis_tool_selectsimilar.h new file mode 100644 index 00000000..10a57dd3 --- /dev/null +++ b/krita/plugins/tools/tool_selectsimilar/kis_tool_selectsimilar.h @@ -0,0 +1,101 @@ +/* + * 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 QWidget; +class QVBoxLayout; +class QCheckBox; +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 + typedef KisToolNonPaint super; + +public: + KisToolSelectSimilar(); + virtual ~KisToolSelectSimilar(); + + virtual void update(KisCanvasSubject *subject); + virtual void setup(KActionCollection *collection); + virtual Q_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 QWidget* createOptionWidget(QWidget* parent); + virtual QWidget* optionWidget(); + + virtual void buttonPress(KisButtonPressEvent *e); + void setPickerCursor(enumSelectionMode); + + KisCanvasSubject *m_subject; + QWidget *m_optWidget; + KisSelectionOptions *m_selectionOptionsWidget; + + int m_fuzziness; + enumSelectionMode m_defaultSelectAction; + enumSelectionMode m_currentSelectAction; + QTimer *m_timer; + QCursor m_addCursor; + QCursor 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/krita/plugins/tools/tool_selectsimilar/kritatoolselectsimilar.desktop b/krita/plugins/tools/tool_selectsimilar/kritatoolselectsimilar.desktop new file mode 100644 index 00000000..a4c48d51 --- /dev/null +++ b/krita/plugins/tools/tool_selectsimilar/kritatoolselectsimilar.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=Krita/Tool +Type=Service +X-KDE-Library=kritatoolselectsimilar +X-Krita-Version=2 diff --git a/krita/plugins/tools/tool_selectsimilar/selectsimilar.cc b/krita/plugins/tools/tool_selectsimilar/selectsimilar.cc new file mode 100644 index 00000000..fc6b0c41 --- /dev/null +++ b/krita/plugins/tools/tool_selectsimilar/selectsimilar.cc @@ -0,0 +1,61 @@ +/* + * selectsimilar.h -- Part of Krita + * + * 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( kritatoolselectsimilar, SelectSimilarFactory( "krita" ) ) + +SelectSimilar::SelectSimilar(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(SelectSimilarFactory::instance()); + + if ( parent->inherits("KisToolRegistry") ) + { + KisToolRegistry * r = dynamic_cast(parent); + r->add(new KisToolSelectSimilarFactory()); + } +} + +SelectSimilar::~SelectSimilar() +{ +} + +#include "selectsimilar.moc" + diff --git a/krita/plugins/tools/tool_selectsimilar/selectsimilar.h b/krita/plugins/tools/tool_selectsimilar/selectsimilar.h new file mode 100644 index 00000000..ca181bcc --- /dev/null +++ b/krita/plugins/tools/tool_selectsimilar/selectsimilar.h @@ -0,0 +1,34 @@ +/* + * selectsimilar.h -- Part of Krita + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * 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 + public: + SelectSimilar(QObject *parent, const char *name, const QStringList &); + virtual ~SelectSimilar(); + + +}; + +#endif // SELECTSIMILAR_H diff --git a/krita/plugins/tools/tool_selectsimilar/tool_similar_selection.png b/krita/plugins/tools/tool_selectsimilar/tool_similar_selection.png new file mode 100644 index 00000000..fd3ae241 Binary files /dev/null and b/krita/plugins/tools/tool_selectsimilar/tool_similar_selection.png differ diff --git a/krita/plugins/tools/tool_selectsimilar/tool_similar_selection.svg b/krita/plugins/tools/tool_selectsimilar/tool_similar_selection.svg new file mode 100644 index 00000000..371f3860 --- /dev/null +++ b/krita/plugins/tools/tool_selectsimilar/tool_similar_selection.svg @@ -0,0 +1,2118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/krita/plugins/tools/tool_selectsimilar/tool_similar_selection_minus_cursor.png b/krita/plugins/tools/tool_selectsimilar/tool_similar_selection_minus_cursor.png new file mode 100644 index 00000000..b8bbc131 Binary files /dev/null and b/krita/plugins/tools/tool_selectsimilar/tool_similar_selection_minus_cursor.png differ diff --git a/krita/plugins/tools/tool_selectsimilar/tool_similar_selection_plus_cursor.png b/krita/plugins/tools/tool_selectsimilar/tool_similar_selection_plus_cursor.png new file mode 100644 index 00000000..aed6796f Binary files /dev/null and b/krita/plugins/tools/tool_selectsimilar/tool_similar_selection_plus_cursor.png differ diff --git a/krita/plugins/tools/tool_star/Makefile.am b/krita/plugins/tools/tool_star/Makefile.am new file mode 100644 index 00000000..8efa1e58 --- /dev/null +++ b/krita/plugins/tools/tool_star/Makefile.am @@ -0,0 +1,36 @@ +kde_services_DATA = kritatoolstar.desktop + +# all_includes must remain last! +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kritatoolstar_la_SOURCES = \ + wdg_tool_star.ui \ + tool_star.cc \ + kis_tool_star.cc + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = kritatoolstar.la + +noinst_HEADERS = \ + tool_star.h \ + kis_tool_star.h + +kritatoolstar_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritatoolstar_la_LIBADD = ../../../libkritacommon.la + +kritatoolstar_la_METASOURCES = AUTO + +KDE_OPTIONS = nofinal + +kritapics_DATA = \ + tool_star.png \ + tool_star_cursor.png + +kritapicsdir = $(kde_datadir)/krita/pics + diff --git a/krita/plugins/tools/tool_star/kis_tool_star.cc b/krita/plugins/tools/tool_star/kis_tool_star.cc new file mode 100644 index 00000000..22e890ac --- /dev/null +++ b/krita/plugins/tools/tool_star/kis_tool_star.cc @@ -0,0 +1,245 @@ +/* + * kis_tool_star.cc -- part of Krita + * + * 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() == 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()); + } + } +} + +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 (); +} + +void KisToolStar::setup(KActionCollection *collection) +{ + m_action = static_cast(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; + } +} + +vKisPoint 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;nratioSpinBox->setValue(m_innerOuterRatio); + + QGridLayout *optionLayout = new QGridLayout(widget, 1, 1); + super::addOptionWidgetLayout(optionLayout); + + optionLayout->addWidget(m_optWidget, 0, 0); + + return widget; +} + +#include "kis_tool_star.moc" diff --git a/krita/plugins/tools/tool_star/kis_tool_star.h b/krita/plugins/tools/tool_star/kis_tool_star.h new file mode 100644 index 00000000..e922aa6c --- /dev/null +++ b/krita/plugins/tools/tool_star/kis_tool_star.h @@ -0,0 +1,100 @@ +/* + * kis_tool_star.h - part of Krita + * + * 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 + +public: + KisToolStar(); + virtual ~KisToolStar(); + + // + // KisCanvasObserver interface + // + + virtual void update (KisCanvasSubject *subject); + + virtual QWidget* createOptionWidget(QWidget* parent); + + // + // KisToolPaint interface + // + + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_SHAPE; } + virtual Q_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 QRect& rc); + +protected: + int m_lineThickness; + + KisPoint m_dragStart; + KisPoint m_dragEnd; + QRect m_final_lines; + + bool m_dragging; + KisImageSP m_currentImage; +private: + vKisPoint starCoordinates(int N, double mx, double my, double x, double y); + Q_INT32 m_innerOuterRatio; + Q_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("starshape", i18n("Star Tool")); } +}; + + +#endif //__KIS_TOOL_STAR_H__ diff --git a/krita/plugins/tools/tool_star/kritatoolstar.desktop b/krita/plugins/tools/tool_star/kritatoolstar.desktop new file mode 100644 index 00000000..08388181 --- /dev/null +++ b/krita/plugins/tools/tool_star/kritatoolstar.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=Krita/Tool +Type=Service +X-KDE-Library=kritatoolstar +X-Krita-Version=2 diff --git a/krita/plugins/tools/tool_star/tool_star.cc b/krita/plugins/tools/tool_star/tool_star.cc new file mode 100644 index 00000000..b264cbde --- /dev/null +++ b/krita/plugins/tools/tool_star/tool_star.cc @@ -0,0 +1,62 @@ +/* + * tool_star.cc -- Part of Krita + * + * 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( kritatoolstar, ToolStarFactory( "krita" ) ) + + +ToolStar::ToolStar(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(ToolStarFactory::instance()); + + if ( parent->inherits("KisToolRegistry") ) + { + KisToolRegistry * r = dynamic_cast( parent ); + r->add(new KisToolStarFactory()); + } + +} + +ToolStar::~ToolStar() +{ +} + +#include "tool_star.moc" diff --git a/krita/plugins/tools/tool_star/tool_star.h b/krita/plugins/tools/tool_star/tool_star.h new file mode 100644 index 00000000..28a44f5c --- /dev/null +++ b/krita/plugins/tools/tool_star/tool_star.h @@ -0,0 +1,42 @@ +/* + * 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 +public: + ToolStar(QObject *parent, const char *name, const QStringList &); + virtual ~ToolStar(); + +private: + + KisView * m_view; + +}; + +#endif // TOOL_STAR_H_ diff --git a/krita/plugins/tools/tool_star/tool_star.png b/krita/plugins/tools/tool_star/tool_star.png new file mode 100644 index 00000000..e8c0e72c Binary files /dev/null and b/krita/plugins/tools/tool_star/tool_star.png differ diff --git a/krita/plugins/tools/tool_star/tool_star_cursor.png b/krita/plugins/tools/tool_star/tool_star_cursor.png new file mode 100644 index 00000000..9503c4c7 Binary files /dev/null and b/krita/plugins/tools/tool_star/tool_star_cursor.png differ diff --git a/krita/plugins/tools/tool_star/wdg_tool_star.ui b/krita/plugins/tools/tool_star/wdg_tool_star.ui new file mode 100644 index 00000000..db7c0e4b --- /dev/null +++ b/krita/plugins/tools/tool_star/wdg_tool_star.ui @@ -0,0 +1,128 @@ + +WdgToolStar + + + WdgToolStar + + + + 0 + 0 + 280 + 50 + + + + Star + + + + unnamed + + + 0 + + + + layout8 + + + + unnamed + + + + textLabel1 + + + Vertices: + + + isbX + + + + + verticesSpinBox + + + 100 + + + 2 + + + 5 + + + + + + + layout7 + + + + 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/krita/plugins/tools/tool_transform/Makefile.am b/krita/plugins/tools/tool_transform/Makefile.am new file mode 100644 index 00000000..8f77620e --- /dev/null +++ b/krita/plugins/tools/tool_transform/Makefile.am @@ -0,0 +1,36 @@ +kde_services_DATA = kritatooltransform.desktop + +# all_includes must remain last! +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kritatooltransform_la_SOURCES = \ + wdg_tool_transform.ui \ + tool_transform.cc \ + kis_tool_transform.cc + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = kritatooltransform.la + +noinst_HEADERS = \ + tool_transform.h \ + kis_tool_transform.h + +kritatooltransform_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritatooltransform_la_LIBADD = ../../../libkritacommon.la + +kritatooltransform_la_METASOURCES = AUTO + +KDE_OPTIONS = nofinal + +kritapics_DATA = \ + rotate_cursor.xpm \ + tool_transform.png + +kritapicsdir = $(kde_datadir)/krita/pics + diff --git a/krita/plugins/tools/tool_transform/kis_tool_transform.cc b/krita/plugins/tools/tool_transform/kis_tool_transform.cc new file mode 100644 index 00000000..05cdfd44 --- /dev/null +++ b/krita/plugins/tools/tool_transform/kis_tool_transform.cc @@ -0,0 +1,916 @@ +/* + * kis_tool_transform.cc -- part of Krita + * + * 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, QPoint startPos, QPoint endPos); + virtual ~TransformCmd(); + + public: + virtual void execute(); + virtual void unexecute(); + void transformArgs(double &sx, double &sy, double &tx, double &ty, double &a); + KisSelectionSP origSelection(QPoint &startPos, QPoint &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; + QPoint m_startPos; + QPoint 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, QPoint startPos, QPoint 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(QPoint &startPos, QPoint &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 = QPoint(0, 0); + m_endPos = QPoint(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(), SIGNAL(sigLayerActivated(KisLayerSP)), this, 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(), SIGNAL(sigLayerActivated(KisLayerSP)), this, SLOT(slotLayerActivated(KisLayerSP))); +} + +void KisToolTransform::initHandles() +{ + Q_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()); + QRect r = sel->selectedExactRect(); + r.rect(&x, &y, &w, &h); + } + else { + dev->exactBounds(x,y,w,h); + m_origSelection = 0; + } + m_startPos = QPoint(x, y); + m_endPos = QPoint(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, QRect()); +} + +void KisToolTransform::paint(KisCanvasPainter& gc, const QRect& rc) +{ + paintOutline(gc, rc); +} + + +void KisToolTransform::buttonPress(KisButtonPressEvent *e) +{ + if (m_subject && e->button() == QMouseEvent::LeftButton) { + m_wasPressed = true; + } + + if (m_subject) { + KisImageSP img = m_subject->currentImg(); + + if (img && img->activeDevice() && e->button() == LeftButton) { + switch(m_function) + { + case ROTATE: + m_clickoffset = e->pos().floorQPoint() + - QPoint(static_cast(m_translateX),static_cast(m_translateY)); + m_clickangle = -m_a - atan2(m_clickoffset.x(),m_clickoffset.y()); + m_clickoffset = QPoint(0, 0); + break; + case MOVE: + m_clickoffset = e->pos().floorQPoint() + - QPoint(static_cast(m_translateX),static_cast(m_translateY)); + break; + case TOPSCALE: + m_clickoffset = e->pos().floorQPoint() + - QPoint((m_topleft + m_topright)/2); + break; + case TOPRIGHTSCALE: + m_clickoffset = e->pos().floorQPoint() - m_topright; + break; + case RIGHTSCALE: + m_clickoffset = e->pos().floorQPoint() + - QPoint((m_topright + m_bottomright)/2); + break; + case BOTTOMRIGHTSCALE: + m_clickoffset = e->pos().floorQPoint() - m_bottomright; + break; + case BOTTOMSCALE: + m_clickoffset = e->pos().floorQPoint() + - QPoint((m_bottomleft + m_bottomright)/2); + break; + case BOTTOMLEFTSCALE: + m_clickoffset = e->pos().floorQPoint() - m_bottomleft; + break; + case LEFTSCALE: + m_clickoffset = e->pos().floorQPoint() + - QPoint((m_topleft + m_bottomleft)/2); + break; + case TOPLEFTSCALE: + m_clickoffset = e->pos().floorQPoint() - m_topleft; + break; + } + m_selecting = true; + m_actualyMoveWhileSelected = false; + } + } +} + +int KisToolTransform::det(QPoint v,QPoint w) +{ + return v.x()*w.y()-v.y()*w.x(); +} +int KisToolTransform::distsq(QPoint v,QPoint 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); + QPoint topleft = m_topleft; + QPoint topright = m_topright; + QPoint bottomleft = m_bottomleft; + QPoint bottomright = m_bottomright; + + QPoint mousePos = e->pos().floorQPoint(); + + 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() & Qt::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() & Qt::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() & Qt::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() & Qt::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() & Qt::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() & Qt::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() & Qt::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() & Qt::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() == QMouseEvent::LeftButton) { + if(!m_wasPressed) return; + m_wasPressed = false; + + KisImageSP img = m_subject->currentImg(); + + if (!img) + return; + + m_selecting = false; + + if(m_actualyMoveWhileSelected) + { + paintOutline(); + QApplication::setOverrideCursor(KisCursor::waitCursor()); + transform(); + QApplication::restoreOverrideCursor(); + } + } +} + +void KisToolTransform::paintOutline() +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + KisCanvas *canvas = controller->kiscanvas(); + KisCanvasPainter gc(canvas); + QRect 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 = QPoint(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 = QPoint(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 = QPoint(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 = QPoint(int(rotX(x,y) + m_translateX+0.5), int(rotY(x,y) + m_translateY+0.5)); +} + +void KisToolTransform::paintOutline(KisCanvasPainter& gc, const QRect&) +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + RasterOp op = gc.rasterOp(); + QPen old = gc.pen(); + QPen pen(Qt::SolidLine); + pen.setWidth(1); + Q_ASSERT(controller); + + recalcOutline(); + QPoint topleft = controller->windowToView(m_topleft); + QPoint topright = controller->windowToView(m_topright); + QPoint bottomleft = controller->windowToView(m_bottomleft); + QPoint bottomright = controller->windowToView(m_bottomright); + + gc.setRasterOp(Qt::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. + QRect 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) + { + //QRect rc = m_origSelection->extent(); + QRect 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(); +} + + +QWidget* KisToolTransform::createOptionWidget(QWidget* parent) +{ + + m_optWidget = new WdgToolTransform(parent); + 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, SIGNAL(activated(const KisID &)), + this, SLOT(slotSetFilter(const KisID &))); + + KisID filterID = m_optWidget->cmbFilter->currentItem(); + m_filter = KisFilterStrategyRegistry::instance()->get(filterID); + +/* + connect(m_optWidget->intStartX, SIGNAL(valueChanged(int)), this, SLOT(setStartX(int))); + connect(m_optWidget->intStartY, SIGNAL(valueChanged(int)), this, SLOT(setStartY(int))); + connect(m_optWidget->intEndX, SIGNAL(valueChanged(int)), this, SLOT(setEndX(int))); + connect(m_optWidget->intEndY, SIGNAL(valueChanged(int)), this, 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; +} + +QWidget* 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, + 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/krita/plugins/tools/tool_transform/kis_tool_transform.h b/krita/plugins/tools/tool_transform/kis_tool_transform.h new file mode 100644 index 00000000..9ae4f4da --- /dev/null +++ b/krita/plugins/tools/tool_transform/kis_tool_transform.h @@ -0,0 +1,154 @@ +/* + * kis_tool_transform.h - part of Krita + * + * 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 + +public: + KisToolTransform(); + virtual ~KisToolTransform(); + + virtual QWidget* createOptionWidget(QWidget* parent); + virtual QWidget* optionWidget(); + + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_TRANSFORM; } + virtual Q_UINT32 priority() { return 3; } + virtual void paint(KisCanvasPainter& gc); + virtual void paint(KisCanvasPainter& gc, const QRect& 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 QRect& 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(QPoint v,QPoint w); + int distsq(QPoint v,QPoint 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}; + QCursor m_sizeCursors[8]; + function m_function; + QPoint m_startPos; + QPoint m_endPos; + bool m_selecting; + bool m_actualyMoveWhileSelected; + QPoint m_topleft; + QPoint m_topright; + QPoint m_bottomleft; + QPoint m_bottomright; + double m_scaleX; + double m_scaleY; + double m_translateX; + double m_translateY; + QPoint 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/krita/plugins/tools/tool_transform/kritatooltransform.desktop b/krita/plugins/tools/tool_transform/kritatooltransform.desktop new file mode 100644 index 00000000..bff56123 --- /dev/null +++ b/krita/plugins/tools/tool_transform/kritatooltransform.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=Krita/Tool +Type=Service +X-KDE-Library=kritatooltransform +X-Krita-Version=2 diff --git a/krita/plugins/tools/tool_transform/rotate_cursor.xpm b/krita/plugins/tools/tool_transform/rotate_cursor.xpm new file mode 100644 index 00000000..f3860232 --- /dev/null +++ b/krita/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/krita/plugins/tools/tool_transform/tool_transform.cc b/krita/plugins/tools/tool_transform/tool_transform.cc new file mode 100644 index 00000000..e8c77aa7 --- /dev/null +++ b/krita/plugins/tools/tool_transform/tool_transform.cc @@ -0,0 +1,64 @@ +/* + * tool_transform.cc -- Part of Krita + * + * 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( kritatooltransform, ToolTransformFactory( "krita" ) ) + + +ToolTransform::ToolTransform(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(ToolTransformFactory::instance()); + + if ( parent->inherits("KisToolRegistry") ) + { + KisToolRegistry * r = dynamic_cast(parent); + KisToolTransformFactory * f = new KisToolTransformFactory(); + Q_CHECK_PTR(f); + r->add(f); + } + +} + +ToolTransform::~ToolTransform() +{ +} + +#include "tool_transform.moc" diff --git a/krita/plugins/tools/tool_transform/tool_transform.h b/krita/plugins/tools/tool_transform/tool_transform.h new file mode 100644 index 00000000..42eba788 --- /dev/null +++ b/krita/plugins/tools/tool_transform/tool_transform.h @@ -0,0 +1,42 @@ +/* + * 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 +public: + ToolTransform(QObject *parent, const char *name, const QStringList &); + virtual ~ToolTransform(); + +private: + + KisView * m_view; + +}; + +#endif // TOOL_TRANSFORM_H_ diff --git a/krita/plugins/tools/tool_transform/tool_transform.png b/krita/plugins/tools/tool_transform/tool_transform.png new file mode 100644 index 00000000..47e58869 Binary files /dev/null and b/krita/plugins/tools/tool_transform/tool_transform.png differ diff --git a/krita/plugins/tools/tool_transform/wdg_tool_transform.ui b/krita/plugins/tools/tool_transform/wdg_tool_transform.ui new file mode 100644 index 00000000..b9307451 --- /dev/null +++ b/krita/plugins/tools/tool_transform/wdg_tool_transform.ui @@ -0,0 +1,243 @@ + +WdgToolTransform + + + WdgToolTransform + + + + 0 + 0 + 377 + 91 + + + + Transform + + + + unnamed + + + 0 + + + 3 + + + + layout11 + + + + unnamed + + + + layout7 + + + + unnamed + + + + layout1 + + + + unnamed + + + + textLabel1 + + + Move X: + + + isbX + + + + + intStartX + + + 1000000000 + + + + + + + layout2 + + + + unnamed + + + + textLabel2 + + + Scale X: + + + isbWidth + + + + + intEndX + + + 1000000000 + + + + + + + + + layout8 + + + + unnamed + + + + layout3 + + + + unnamed + + + + textLabel3 + + + Move Y: + + + isbY + + + + + intStartY + + + 1000000000 + + + + + + + layout4 + + + + 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/krita/plugins/viewplugins/Makefile.am b/krita/plugins/viewplugins/Makefile.am new file mode 100644 index 00000000..e5739b36 --- /dev/null +++ b/krita/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/krita/plugins/viewplugins/colorrange/Makefile.am b/krita/plugins/viewplugins/colorrange/Makefile.am new file mode 100644 index 00000000..90a260a3 --- /dev/null +++ b/krita/plugins/viewplugins/colorrange/Makefile.am @@ -0,0 +1,24 @@ +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = kritacolorrange.la + +kritacolorrange_la_SOURCES = colorrange.cc dlg_colorrange.cc wdg_colorrange.ui +noinst_HEADERS = wdg_colorrange.h dlg_colorrange.h colorrange.h + +kritacolorrange_la_LIBADD = ../../../libkritacommon.la +kritacolorrange_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) + +kritarcdir = $(kde_datadir)/kritaplugins +kritarc_DATA = colorrange.rc +EXTRA_DIST = $(kritarc_DATA) + +kde_services_DATA = kritacolorrange.desktop + +kritacolorrange_la_METASOURCES = AUTO + +KDE_OPTIONS = nofinal diff --git a/krita/plugins/viewplugins/colorrange/colorrange.cc b/krita/plugins/viewplugins/colorrange/colorrange.cc new file mode 100644 index 00000000..9c52e027 --- /dev/null +++ b/krita/plugins/viewplugins/colorrange/colorrange.cc @@ -0,0 +1,82 @@ +/* + * colorrange.h -- Part of Krita + * + * 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( kritacolorrange, ColorRangeFactory( "krita" ) ) + +ColorRange::ColorRange(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + + if (parent->inherits("KisView")) { + setInstance(ColorRangeFactory::instance()); + setXMLFile(locate("data","kritaplugins/colorrange.rc"), true); + m_view = dynamic_cast(parent); + m_view->canvasSubject()->selectionManager()->addSelectionAction( new KAction(i18n("&Color Range..."), 0, 0, this, 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/krita/plugins/viewplugins/colorrange/colorrange.h b/krita/plugins/viewplugins/colorrange/colorrange.h new file mode 100644 index 00000000..1cc10cef --- /dev/null +++ b/krita/plugins/viewplugins/colorrange/colorrange.h @@ -0,0 +1,44 @@ +/* + * colorrange.h -- Part of Krita + * + * 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 + public: + ColorRange(QObject *parent, const char *name, const QStringList &); + virtual ~ColorRange(); + + private slots: + void slotActivated(); + + private: + KisView * m_view; + KisPainter * m_painter; + +}; + +#endif // COLORRANGE_H diff --git a/krita/plugins/viewplugins/colorrange/colorrange.rc b/krita/plugins/viewplugins/colorrange/colorrange.rc new file mode 100644 index 00000000..344fad33 --- /dev/null +++ b/krita/plugins/viewplugins/colorrange/colorrange.rc @@ -0,0 +1,10 @@ + + + + Select + + + + + + diff --git a/krita/plugins/viewplugins/colorrange/dlg_colorrange.cc b/krita/plugins/viewplugins/colorrange/dlg_colorrange.cc new file mode 100644 index 00000000..1cd115c1 --- /dev/null +++ b/krita/plugins/viewplugins/colorrange/dlg_colorrange.cc @@ -0,0 +1,351 @@ +/* + * dlg_colorrange.cc - part of KimageShop^WKrayon^WKrita + * + * 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); + } + +} + +Q_UINT32 matchColors(const QColor & 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, QWidget * parent, const char * name) + : super (parent, 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->sizeHint()); + + 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, SIGNAL(okClicked()), + this, SLOT(okClicked())); + + connect(this, SIGNAL(cancelClicked()), + this, SLOT(cancelClicked())); + + connect(m_page->chkInvert, SIGNAL(clicked()), + this, SLOT(slotInvertClicked())); + + connect(m_page->cmbSelect, SIGNAL(activated(int)), + this, SLOT(slotSelectionTypeChanged(int))); + + connect (m_page->radioAdd, SIGNAL(toggled(bool)), + this, SLOT(slotAdd(bool))); + + connect (m_page->radioSubtract, SIGNAL(toggled(bool)), + this, SLOT(slotSubtract(bool))); + + connect (m_page->bnSelect, SIGNAL(clicked()), + this, SLOT(slotSelectClicked())); + + connect (m_page->bnDeselect, SIGNAL(clicked()), + this, SLOT(slotDeselectClicked())); + +} + +DlgColorRange::~DlgColorRange() +{ + delete m_page; +} + + +void DlgColorRange::updatePreview() +{ + if (!m_selection) return; + + Q_INT32 x, y, w, h; + m_dev->exactBounds(x, y, w, h); + QPixmap pix = QPixmap(m_selection->maskImage().smoothScale(350, 350, QImage::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() +{ + QApplication::setOverrideCursor(KisCursor::waitCursor()); + // XXX: Multithread this! + Q_INT32 x, y, w, h; + m_dev->exactBounds(x, y, w, h); + KisColorSpace * cs = m_dev->colorSpace(); + Q_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()) { + QColor c; + + cs->toQColor(hiter.rawData(), &c, &opacity); + // Don't try to select transparent pixels. + if (opacity > OPACITY_TRANSPARENT) { + Q_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) { + Q_UINT8 selectedness = *(selIter.rawData()); + if (match < selectedness) { + *(selIter.rawData()) = selectedness - match; + } + else { + *(selIter.rawData()) = 0; + } + } + } + else { + if (m_mode == SELECTION_ADD) { + Q_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(); + QApplication::restoreOverrideCursor(); +} + +void DlgColorRange::slotDeselectClicked() +{ + m_dev->selection()->clear(); + updatePreview(); +} + + +#include "dlg_colorrange.moc" diff --git a/krita/plugins/viewplugins/colorrange/dlg_colorrange.h b/krita/plugins/viewplugins/colorrange/dlg_colorrange.h new file mode 100644 index 00000000..5a792abd --- /dev/null +++ b/krita/plugins/viewplugins/colorrange/dlg_colorrange.h @@ -0,0 +1,99 @@ +/* + * dlg_colorrange.h -- part of KimageShop^WKrayon^WKrita + * + * 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 mask based + * on a (range of) colors. + */ +class DlgColorRange: public KDialogBase { + typedef KDialogBase super; + Q_OBJECT + + + +public: + + DlgColorRange(KisView * view, KisPaintDeviceSP layer, QWidget * parent = 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: + QImage createMask(KisSelectionSP selection, KisPaintDeviceSP layer); + +private: + + WdgColorRange * m_page; + KisSelectionSP m_selection; + KisPaintDeviceSP m_dev; + KisView * m_view; + KisCanvasSubject * m_subject; + enumSelectionMode m_mode; + QCursor m_oldCursor; + KisSelectedTransaction *m_transaction; + enumAction m_currentAction; + bool m_invert; +}; + + +#endif // DLG_COLORRANGE diff --git a/krita/plugins/viewplugins/colorrange/kritacolorrange.desktop b/krita/plugins/viewplugins/colorrange/kritacolorrange.desktop new file mode 100644 index 00000000..22b070eb --- /dev/null +++ b/krita/plugins/viewplugins/colorrange/kritacolorrange.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=Krita/ViewPlugin +Type=Service +X-KDE-Library=kritacolorrange +X-Krita-Version=2 diff --git a/krita/plugins/viewplugins/colorrange/wdg_colorrange.ui b/krita/plugins/viewplugins/colorrange/wdg_colorrange.ui new file mode 100644 index 00000000..e9ed74f5 --- /dev/null +++ b/krita/plugins/viewplugins/colorrange/wdg_colorrange.ui @@ -0,0 +1,252 @@ + +WdgColorRange + + + WdgColorRange + + + + 0 + 0 + 515 + 528 + + + + Color Range + + + + unnamed + + + + layout10 + + + + unnamed + + + + layout8 + + + + unnamed + + + + layout7 + + + + 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 + + + + + + + + + layout9 + + + + 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/krita/plugins/viewplugins/colorspaceconversion/Makefile.am b/krita/plugins/viewplugins/colorspaceconversion/Makefile.am new file mode 100644 index 00000000..a3f9bd93 --- /dev/null +++ b/krita/plugins/viewplugins/colorspaceconversion/Makefile.am @@ -0,0 +1,26 @@ +kritarcdir = $(kde_datadir)/kritaplugins +kritarc_DATA = colorspaceconversion.rc + +EXTRA_DIST = $(kritarc_DATA) + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + + +kde_module_LTLIBRARIES = kritacolorspaceconversion.la + +kritacolorspaceconversion_la_SOURCES = wdgconvertcolorspace.ui colorspaceconversion.cc dlg_colorspaceconversion.cc +noinst_HEADERS = wdgconvertcolorspace.h dlg_colorspaceconversion.h colorspaceconversion.h + +kritacolorspaceconversion_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritacolorspaceconversion_la_LIBADD = ../../../libkritacommon.la + +kritacolorspaceconversion_la_METASOURCES = AUTO + +kde_services_DATA = kritacolorspaceconversion.desktop + diff --git a/krita/plugins/viewplugins/colorspaceconversion/colorspaceconversion.cc b/krita/plugins/viewplugins/colorspaceconversion/colorspaceconversion.cc new file mode 100644 index 00000000..62528a0c --- /dev/null +++ b/krita/plugins/viewplugins/colorspaceconversion/colorspaceconversion.cc @@ -0,0 +1,155 @@ +/* + * colorspaceconversion.cc -- Part of Krita + * + * 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( kritacolorspaceconversion, ColorSpaceConversionFactory( "krita" ) ) + + +ColorSpaceConversion::ColorSpaceConversion(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + + if ( parent->inherits("KisView") ) + { + m_view = (KisView*) parent; + + setInstance(ColorSpaceConversionFactory::instance()); + setXMLFile(locate("data","kritaplugins/colorspaceconversion.rc"), true); + + (void) new KAction(i18n("&Convert Image Type..."), 0, 0, this, SLOT(slotImgColorSpaceConversion()), actionCollection(), "imgcolorspaceconversion"); + (void) new KAction(i18n("&Convert Layer Type..."), 0, 0, this, 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") + .arg(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() == QDialog::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()); + + QApplication::setOverrideCursor(KisCursor::waitCursor()); + image->convertTo(cs, dlgColorSpaceConversion->m_page->grpIntent->selectedId()); + QApplication::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") + .arg(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() == QDialog::Accepted) { + KisID cspace = dlgColorSpaceConversion->m_page->cmbColorSpaces->currentItem(); + KisColorSpace * cs = KisMetaRegistry::instance()->csRegistry() -> + getColorSpace(cspace, dlgColorSpaceConversion->m_page->cmbDestProfile->currentText()); + + QApplication::setOverrideCursor(KisCursor::waitCursor()); + dev->convertTo(cs, dlgColorSpaceConversion->m_page->grpIntent->selectedId()); + QApplication::restoreOverrideCursor(); + } + delete dlgColorSpaceConversion; +} + +#include "colorspaceconversion.moc" diff --git a/krita/plugins/viewplugins/colorspaceconversion/colorspaceconversion.h b/krita/plugins/viewplugins/colorspaceconversion/colorspaceconversion.h new file mode 100644 index 00000000..3bf85530 --- /dev/null +++ b/krita/plugins/viewplugins/colorspaceconversion/colorspaceconversion.h @@ -0,0 +1,50 @@ +/* + * colorspaceconversion.h -- Part of Krita + * + * 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 +public: + ColorSpaceConversion(QObject *parent, const char *name, const QStringList &); + virtual ~ColorSpaceConversion(); + +private slots: + + void slotImgColorSpaceConversion(); + void slotLayerColorSpaceConversion(); + +private: + + KisView * m_view; + KisPainter * m_painter; + +}; + +#endif // COLORSPACECONVERSION_H diff --git a/krita/plugins/viewplugins/colorspaceconversion/colorspaceconversion.rc b/krita/plugins/viewplugins/colorspaceconversion/colorspaceconversion.rc new file mode 100644 index 00000000..01feae6c --- /dev/null +++ b/krita/plugins/viewplugins/colorspaceconversion/colorspaceconversion.rc @@ -0,0 +1,11 @@ + + + + &Image + + + La&yer + + + + diff --git a/krita/plugins/viewplugins/colorspaceconversion/dlg_colorspaceconversion.cc b/krita/plugins/viewplugins/colorspaceconversion/dlg_colorspaceconversion.cc new file mode 100644 index 00000000..b59fb546 --- /dev/null +++ b/krita/plugins/viewplugins/colorspaceconversion/dlg_colorspaceconversion.cc @@ -0,0 +1,91 @@ +/* + * dlg_colorspaceconversion.cc - part of KimageShop^WKrayon^WKrita + * + * 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( QWidget * parent, + const char * name) + : super (parent, 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->sizeHint()); + + m_page->cmbColorSpaces->setIDList(KisMetaRegistry::instance()->csRegistry()->listKeys()); + + fillCmbDestProfile(m_page->cmbColorSpaces->currentItem()); + + connect(m_page->cmbColorSpaces, SIGNAL(activated(const KisID &)), + this, SLOT(fillCmbDestProfile(const KisID &))); + + + connect(this, SIGNAL(okClicked()), + this, SLOT(okClicked())); + +} + +DlgColorSpaceConversion::~DlgColorSpaceConversion() +{ + delete m_page; +} + +// SLOTS + +void DlgColorSpaceConversion::okClicked() +{ + accept(); +} + + +void DlgColorSpaceConversion::fillCmbDestProfile(const KisID & s) +{ + m_page->cmbDestProfile->clear(); + + QValueVector profileList = KisMetaRegistry::instance()->csRegistry()->profilesFor(s); + QValueVector ::iterator it; + for ( it = profileList.begin(); it != profileList.end(); ++it ) { + m_page->cmbDestProfile->insertItem((*it)->productName()); + + } +} + + +#include "dlg_colorspaceconversion.moc" diff --git a/krita/plugins/viewplugins/colorspaceconversion/dlg_colorspaceconversion.h b/krita/plugins/viewplugins/colorspaceconversion/dlg_colorspaceconversion.h new file mode 100644 index 00000000..ed086a8d --- /dev/null +++ b/krita/plugins/viewplugins/colorspaceconversion/dlg_colorspaceconversion.h @@ -0,0 +1,49 @@ +/* + * dlg_colorspaceconversion.h -- part of KimageShop^WKrayon^WKrita + * + * 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 + +public: + + DlgColorSpaceConversion(QWidget * parent = 0, const char* name = 0); + ~DlgColorSpaceConversion(); + + WdgConvertColorSpace * m_page; + +public slots: + + void okClicked(); + void fillCmbDestProfile(const KisID &); +}; + +#endif // DLG_COLORSPACECONVERSION diff --git a/krita/plugins/viewplugins/colorspaceconversion/kritacolorspaceconversion.desktop b/krita/plugins/viewplugins/colorspaceconversion/kritacolorspaceconversion.desktop new file mode 100644 index 00000000..15436a12 --- /dev/null +++ b/krita/plugins/viewplugins/colorspaceconversion/kritacolorspaceconversion.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=Krita/ViewPlugin +Type=Service +X-KDE-Library=kritacolorspaceconversion +X-Krita-Version=2 diff --git a/krita/plugins/viewplugins/colorspaceconversion/wdgconvertcolorspace.ui b/krita/plugins/viewplugins/colorspaceconversion/wdgconvertcolorspace.ui new file mode 100644 index 00000000..31f29be5 --- /dev/null +++ b/krita/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/krita/plugins/viewplugins/dropshadow/Makefile.am b/krita/plugins/viewplugins/dropshadow/Makefile.am new file mode 100644 index 00000000..c339627e --- /dev/null +++ b/krita/plugins/viewplugins/dropshadow/Makefile.am @@ -0,0 +1,30 @@ +kritarcdir = $(kde_datadir)/kritaplugins +kritarc_DATA = dropshadow.rc +EXTRA_DIST = $(kritarc_DATA) + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../colorspaces/rgb_u8 \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + + +kde_module_LTLIBRARIES = kritadropshadow.la + +kritadropshadow_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 + +kritadropshadow_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritadropshadow_la_LIBADD = ../../../libkritacommon.la ../../../colorspaces/rgb_u8/libkritargb.la + +kde_services_DATA = kritadropshadow.desktop + +kritadropshadow_la_METASOURCES = AUTO + +KDE_OPTIONS = nofinal diff --git a/krita/plugins/viewplugins/dropshadow/dlg_dropshadow.cc b/krita/plugins/viewplugins/dropshadow/dlg_dropshadow.cc new file mode 100644 index 00000000..545f886f --- /dev/null +++ b/krita/plugins/viewplugins/dropshadow/dlg_dropshadow.cc @@ -0,0 +1,117 @@ +/* + * dlg_dropshadow.cc - part of KimageShop^WKrayon^WKrita + * + * 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 QString & /*imageCS*/, + const QString & /*layerCS*/, + QWidget * parent, + const char * name) + : super (parent, 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->sizeHint()); + + 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) ); + QColor 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, SIGNAL(okClicked()), + this, SLOT(okClicked())); +} + +DlgDropshadow::~DlgDropshadow() +{ + delete m_page; +} + +Q_INT32 DlgDropshadow::getXOffset() +{ + return m_page->xOffsetSpinBox->value(); +} + +Q_INT32 DlgDropshadow::getYOffset() +{ + return m_page->yOffsetSpinBox->value(); +} + +Q_INT32 DlgDropshadow::getBlurRadius() +{ + return m_page->blurRadiusSpinBox->value(); +} + +Q_UINT8 DlgDropshadow::getShadowOpacity() +{ + double opacity = (double)m_page->opacitySpinBox->value(); + //convert percent to a 8 bit opacity value + return (Q_UINT8)(opacity / 100 * 255); +} + +QColor 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/krita/plugins/viewplugins/dropshadow/dlg_dropshadow.h b/krita/plugins/viewplugins/dropshadow/dlg_dropshadow.h new file mode 100644 index 00000000..8e514658 --- /dev/null +++ b/krita/plugins/viewplugins/dropshadow/dlg_dropshadow.h @@ -0,0 +1,59 @@ +/* + * dlg_dropshadow.h -- part of KimageShop^WKrayon^WKrita + * + * 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 QColor; + +/** + * 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 + +public: + + DlgDropshadow(const QString & imageCS, const QString & layerCS, QWidget * parent = 0, + const char* name = 0); + ~DlgDropshadow(); + +public: + + Q_INT32 getXOffset(); + Q_INT32 getYOffset(); + Q_INT32 getBlurRadius(); + Q_UINT8 getShadowOpacity(); + QColor getShadowColor(); + bool allowResizingChecked(); +private slots: + void okClicked(); + +private: + + WdgDropshadow * m_page; +}; + +#endif // DLG_DROPSHADOW diff --git a/krita/plugins/viewplugins/dropshadow/dropshadow.rc b/krita/plugins/viewplugins/dropshadow/dropshadow.rc new file mode 100644 index 00000000..e5a446b2 --- /dev/null +++ b/krita/plugins/viewplugins/dropshadow/dropshadow.rc @@ -0,0 +1,11 @@ + + + + La&yer + + Layer Effects + + + + + diff --git a/krita/plugins/viewplugins/dropshadow/kis_dropshadow.cc b/krita/plugins/viewplugins/dropshadow/kis_dropshadow.cc new file mode 100644 index 00000000..7881f568 --- /dev/null +++ b/krita/plugins/viewplugins/dropshadow/kis_dropshadow.cc @@ -0,0 +1,758 @@ +/* + * This file is part of Krita + * + * 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, Q_INT32 xoffset, Q_INT32 yoffset, Q_INT32 blurradius, QColor color, Q_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()); + + QRect rect = dev->exactBounds(); + + for (Q_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 + Q_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 parent = image->rootLayer(); + if (image->activeLayer()) + parent = image->activeLayer()->parent().data(); + + KisPaintLayerSP l = new KisPaintLayer(image, i18n("Drop Shadow"), opacity, shadowDev); + image->addLayer( l.data(), parent, src->siblingBelow() ); + + if (allowResize) + { + QRect shadowBounds = shadowDev->exactBounds(); + + if (!image->bounds().contains(shadowBounds)) { + + QRect newImageSize = image->bounds() | shadowBounds; + image->resize(newImageSize.width(), newImageSize.height()); + + if (shadowBounds.left() < 0 || shadowBounds.top() < 0) { + + Q_INT32 newRootX = image->rootLayer()->x(); + Q_INT32 newRootY = image->rootLayer()->y(); + + if (shadowBounds.left() < 0) { + newRootX += -shadowBounds.left(); + } + if (shadowBounds.top() < 0) { + newRootY += -shadowBounds.top(); + } + + KCommand *moveCommand = image->rootLayer()->moveCommand(QPoint(image->rootLayer()->x(), image->rootLayer()->y()), + QPoint(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, QRect& rect, double horz, double vert, BlurMethod method, KisProgressDisplayInterface *) +{ + Q_INT32 width, height; + Q_INT32 bytes; + Q_UINT8 *dest, *dp; + Q_UINT8 *src, *sp, *sp_p, *sp_m; + Q_INT32 *buf = NULL; + Q_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; + Q_INT32 x1, y1, x2, y2; + Q_INT32 i, j; + Q_INT32 row, col, b; + Q_INT32 terms; + double progress, max_progress; + Q_INT32 initial_p[4]; + Q_INT32 initial_m[4]; + double std_dev; + Q_INT32 pixels; + Q_INT32 total = 1; + Q_INT32 start, end; + Q_INT32 *curve; + Q_INT32 *sum = NULL; + Q_INT32 val; + Q_INT32 length; + Q_INT32 initial_pp, initial_mm; + + x1 = (Q_INT32)(rect.x() - horz); + y1 = (Q_INT32)(rect.y() - vert); + width = (Q_INT32)(rect.width() + 2 * horz); + height = (Q_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 Q_INT32[MAX (width, height) * 2]; + break; + } + + src = new Q_UINT8[MAX (width, height) * bytes]; + dest = new Q_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 Q_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( (Q_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 Q_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( (Q_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) +{ + Q_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, Q_UINT8 *dest, Q_INT32 bytes, Q_INT32 width) +{ + Q_INT32 b; + Q_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++ = (Q_UINT8) sum; + } +} + +//The equations: g(r) = exp (- r^2 / (2 * sigma^2)), r = sqrt (x^2 + y ^2) +Q_INT32 * KisDropshadow::make_curve(double sigma, Q_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 Q_INT32[n]; + + *length = n / 2; + curve += *length; + curve[0] = 255; + + for (i = 1; i <= *length; i++) + { + temp = (Q_INT32) (exp (- (i * i) / sigma2) * 255); + curve[-i] = temp; + curve[i] = temp; + } + + return curve; +} + +void KisDropshadow::run_length_encode (Q_UINT8 *src, Q_INT32 *dest, Q_INT32 bytes, Q_INT32 width) +{ + Q_INT32 start; + Q_INT32 i; + Q_INT32 j; + Q_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 (Q_UINT8 *buf, Q_INT32 width, Q_INT32 bytes) +{ + Q_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] = (Q_UINT8)a; + } + } +} + +void KisDropshadow::separate_alpha (Q_UINT8 *buf, Q_INT32 width, Q_INT32 bytes) +{ + Q_INT32 i, j; + Q_UINT8 alpha; + double recip_alpha; + Q_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 = (Q_UINT32)(buf[i + j] * recip_alpha); + buf[i + j] = MIN (255, new_val); + } + } + } +} + +#include "kis_dropshadow.moc" diff --git a/krita/plugins/viewplugins/dropshadow/kis_dropshadow.h b/krita/plugins/viewplugins/dropshadow/kis_dropshadow.h new file mode 100644 index 00000000..3aca424f --- /dev/null +++ b/krita/plugins/viewplugins/dropshadow/kis_dropshadow.h @@ -0,0 +1,71 @@ +/* + * 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 QColor; +class KisView; +class KisProgressDisplayInterface; + +class KisDropshadow : public KisProgressSubject { + + Q_OBJECT + +public: + + KisDropshadow(KisView * view); + virtual ~KisDropshadow() {}; + + void dropshadow(KisProgressDisplayInterface * progress, Q_INT32 xoffset, Q_INT32 yoffset, Q_INT32 blurradius, QColor color, Q_UINT8 opacity, bool allowResize); + +public: // Implement KisProgressSubject + virtual void cancel() { m_cancelRequested = true; } + +private: + void gaussianblur (KisPaintDeviceSP src, KisPaintDeviceSP dst, + QRect& 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, Q_UINT8 *dest, Q_INT32 bytes, Q_INT32 width); + Q_INT32* make_curve(double sigma, Q_INT32 *length); + void run_length_encode (Q_UINT8 *src, Q_INT32 *dest, Q_INT32 bytes, Q_INT32 width); + void multiply_alpha (Q_UINT8 *buf, Q_INT32 width, Q_INT32 bytes); + void separate_alpha (Q_UINT8 *buf, Q_INT32 width, Q_INT32 bytes); + +private: + KisView * m_view; + bool m_cancelRequested; + +}; + +#endif diff --git a/krita/plugins/viewplugins/dropshadow/kis_dropshadow_plugin.cc b/krita/plugins/viewplugins/dropshadow/kis_dropshadow_plugin.cc new file mode 100644 index 00000000..efe01a95 --- /dev/null +++ b/krita/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( kritadropshadow, KGenericFactory( "krita" ) ) + +KisDropshadowPlugin::KisDropshadowPlugin(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + if ( parent->inherits("KisView") ) { + + setInstance(KGenericFactory::instance()); + setXMLFile(locate("data","kritaplugins/dropshadow.rc"), true); + + m_view = (KisView*) parent; + (void) new KAction(i18n("Add Drop Shadow..."), 0, 0, this, 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() == QDialog::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/krita/plugins/viewplugins/dropshadow/kis_dropshadow_plugin.h b/krita/plugins/viewplugins/dropshadow/kis_dropshadow_plugin.h new file mode 100644 index 00000000..fd64acdb --- /dev/null +++ b/krita/plugins/viewplugins/dropshadow/kis_dropshadow_plugin.h @@ -0,0 +1,45 @@ +/* + * This file is part of Krita + * + * 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 +public: + KisDropshadowPlugin(QObject *parent, const char *name, const QStringList &); + virtual ~KisDropshadowPlugin(); + +private slots: + + void slotDropshadow(); + +private: + + KisView * m_view; +}; + +#endif diff --git a/krita/plugins/viewplugins/dropshadow/kritadropshadow.desktop b/krita/plugins/viewplugins/dropshadow/kritadropshadow.desktop new file mode 100644 index 00000000..cec20727 --- /dev/null +++ b/krita/plugins/viewplugins/dropshadow/kritadropshadow.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=Krita/ViewPlugin +Type=Service +X-KDE-Library=kritadropshadow +X-Krita-Version=2 diff --git a/krita/plugins/viewplugins/dropshadow/wdg_dropshadow.ui b/krita/plugins/viewplugins/dropshadow/wdg_dropshadow.ui new file mode 100644 index 00000000..d78999c8 --- /dev/null +++ b/krita/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/krita/plugins/viewplugins/filtersgallery/Makefile.am b/krita/plugins/viewplugins/filtersgallery/Makefile.am new file mode 100644 index 00000000..5c463f96 --- /dev/null +++ b/krita/plugins/viewplugins/filtersgallery/Makefile.am @@ -0,0 +1,25 @@ +kritarcdir = $(kde_datadir)/kritaplugins +kritarc_DATA = kritafiltersgallery.rc + +EXTRA_DIST = $(kritarc_DATA) + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + -I../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kritafiltersgallery_la_SOURCES = filters_gallery.cc \ + kis_dlg_filtersgallery.cc kis_wdg_filtersgallery.ui + +kde_module_LTLIBRARIES = kritafiltersgallery.la +noinst_HEADERS = filters_gallery.h kis_dlg_filtersgallery.h + +kde_services_DATA = kritafiltersgallery.desktop + +kritafiltersgallery_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritafiltersgallery_la_LIBADD = ../../../libkritacommon.la + +kritafiltersgallery_la_METASOURCES = AUTO diff --git a/krita/plugins/viewplugins/filtersgallery/filters_gallery.cc b/krita/plugins/viewplugins/filtersgallery/filters_gallery.cc new file mode 100644 index 00000000..f0849807 --- /dev/null +++ b/krita/plugins/viewplugins/filtersgallery/filters_gallery.cc @@ -0,0 +1,138 @@ +/* + * This file is part of Krita + * + * 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 Krita { +namespace Plugins { +namespace FiltersGallery { + +typedef KGenericFactory KritaFiltersGalleryFactory; +K_EXPORT_COMPONENT_FACTORY( kritafiltersgallery, KritaFiltersGalleryFactory( "krita" ) ) + +KritaFiltersGallery::KritaFiltersGallery(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + + if ( parent->inherits("KisView") ) + { + setInstance(KritaFiltersGallery::instance()); + setXMLFile(locate("data","kritaplugins/kritafiltersgallery.rc"), true); + + m_view = (KisView*) parent; + + (void) new KAction(i18n("&Filters Gallery"), 0, 0, this, SLOT(showFiltersGalleryDialog()), actionCollection(), "krita_filters_gallery"); + + // Add a docker with the list of filters +// QImage img; +// if(img.load(locate("data","krita/images/previewfilter.png"))) +// { +// KisPaintDeviceSP preview = new KisPaintDevice(KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA",""),"")); +// preview->convertFromQImage(img,""); +// m_view->canvasSubject()->paletteManager()->addWidget(new KisFiltersListView(preview,m_view),"filterslist",krita::EFFECTSBOX, 0); +// } + + } + + +} + +KritaFiltersGallery::~KritaFiltersGallery() +{ +} + +void KritaFiltersGallery::showFiltersGalleryDialog() +{ + KisDlgFiltersGallery dlg(m_view, m_view); + if (dlg.exec()) + { + QApplication::setOverrideCursor( Qt::waitCursor ); + + KisFilter* filter = dlg.currentFilter(); + if(filter ) + { + KisImageSP img = m_view->canvasSubject()->currentImg(); + if (!img) return; + + KisPaintDeviceSP dev = img->activeDevice(); + if (!dev) return; + QRect r1 = dev->exactBounds(); + QRect r2 = img->bounds(); + + QRect rect = r1.intersect(r2); + + if (dev->hasSelection()) { + QRect 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(); + QApplication::restoreOverrideCursor(); + + } + } +} + +} +} +} + +#include "filters_gallery.moc" diff --git a/krita/plugins/viewplugins/filtersgallery/filters_gallery.h b/krita/plugins/viewplugins/filtersgallery/filters_gallery.h new file mode 100644 index 00000000..0e45e582 --- /dev/null +++ b/krita/plugins/viewplugins/filtersgallery/filters_gallery.h @@ -0,0 +1,53 @@ +/* + * This file is part of Krita + * + * 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 Krita { +namespace Plugins { +namespace FiltersGallery { + class KritaFiltersGallery : public KParts::Plugin + { + Q_OBJECT + public: + KritaFiltersGallery(QObject *parent, const char *name, const QStringList &); + virtual ~KritaFiltersGallery(); + public slots: + void showFiltersGalleryDialog(); + private: + + KisView * m_view; + + + }; + +} +} +} + + + +#endif diff --git a/krita/plugins/viewplugins/filtersgallery/kis_dlg_filtersgallery.cc b/krita/plugins/viewplugins/filtersgallery/kis_dlg_filtersgallery.cc new file mode 100644 index 00000000..bb7c20ee --- /dev/null +++ b/krita/plugins/viewplugins/filtersgallery/kis_dlg_filtersgallery.cc @@ -0,0 +1,133 @@ +/* + * This file is part of Krita + * + * 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 Krita { +namespace Plugins { +namespace FiltersGallery { + + +KisDlgFiltersGallery::KisDlgFiltersGallery(KisView* view, QWidget* parent,const char *name) + : KDialogBase(parent,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 , SIGNAL(selectionChanged(QIconViewItem*)), this, SLOT(selectionHasChanged(QIconViewItem* ))); + // Initialize configWidgetHolder + m_widget->configWidgetHolder->setColumnLayout ( 0, Qt::Horizontal ); + //m_widget->configWidgetHolder->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::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, SIGNAL(updated()), this, SLOT(refreshPreview())); + resize( minimumSizeHint()); + m_widget->previewWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::MinimumExpanding); + m_labelNoCW = new QLabel(i18n("No configuration options are available for this filter."), m_widget->configWidgetHolder); + m_widget->configWidgetHolder->layout()->add(m_labelNoCW); + m_labelNoCW->hide(); +} + +KisDlgFiltersGallery::~KisDlgFiltersGallery() +{ +} + +void KisDlgFiltersGallery::selectionHasChanged ( QIconViewItem * item ) +{ + KisFiltersIconViewItem* kisitem = (KisFiltersIconViewItem*) item; + m_currentFilter = kisitem->filter(); + if(m_currentConfigWidget != 0) + { + m_widget->configWidgetHolder->layout()->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->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + m_widget->configWidgetHolder->layout()->add(m_currentConfigWidget); + m_currentConfigWidget->show(); + connect(m_currentConfigWidget, SIGNAL(sigPleaseUpdatePreview()), this, 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/krita/plugins/viewplugins/filtersgallery/kis_dlg_filtersgallery.h b/krita/plugins/viewplugins/filtersgallery/kis_dlg_filtersgallery.h new file mode 100644 index 00000000..a6a216ca --- /dev/null +++ b/krita/plugins/viewplugins/filtersgallery/kis_dlg_filtersgallery.h @@ -0,0 +1,68 @@ +/* + * This file is part of Krita + * + * 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 QIconViewItem; +class QLabel; +class QHBoxLayout; +class KisPreviewWidget; +class KisWdgFiltersGallery; +class KisFiltersListView; + +namespace Krita { +namespace Plugins { +namespace FiltersGallery { + +/** +@author Cyrille Berger +*/ +class KisDlgFiltersGallery : public KDialogBase +{ + Q_OBJECT + public: + KisDlgFiltersGallery(KisView* view, QWidget* parent,const char *name = ""); + ~KisDlgFiltersGallery(); + public: + inline KisFilter* currentFilter() { return m_currentFilter; }; + inline QWidget* currentConfigWidget() { return m_currentConfigWidget; } + private slots: + void slotConfigChanged(); + void refreshPreview(); + void selectionHasChanged ( QIconViewItem * item ); + private: + KisWdgFiltersGallery* m_widget; + KisView* m_view; + QWidget* m_currentConfigWidget; + KisFilter* m_currentFilter; + QLabel* m_labelNoCW; +}; + +} +} +} + +#endif diff --git a/krita/plugins/viewplugins/filtersgallery/kis_wdg_filtersgallery.ui b/krita/plugins/viewplugins/filtersgallery/kis_wdg_filtersgallery.ui new file mode 100644 index 00000000..35553294 --- /dev/null +++ b/krita/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/krita/plugins/viewplugins/filtersgallery/kritafiltersgallery.desktop b/krita/plugins/viewplugins/filtersgallery/kritafiltersgallery.desktop new file mode 100644 index 00000000..8d60672f --- /dev/null +++ b/krita/plugins/viewplugins/filtersgallery/kritafiltersgallery.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=Krita/ViewPlugin +Type=Service +X-KDE-Library=kritafiltersgallery +X-Krita-Version=2 diff --git a/krita/plugins/viewplugins/filtersgallery/kritafiltersgallery.rc b/krita/plugins/viewplugins/filtersgallery/kritafiltersgallery.rc new file mode 100644 index 00000000..6a35a631 --- /dev/null +++ b/krita/plugins/viewplugins/filtersgallery/kritafiltersgallery.rc @@ -0,0 +1,9 @@ + + + +&Filter + + + + + diff --git a/krita/plugins/viewplugins/histogram/Makefile.am b/krita/plugins/viewplugins/histogram/Makefile.am new file mode 100644 index 00000000..a8dd17a1 --- /dev/null +++ b/krita/plugins/viewplugins/histogram/Makefile.am @@ -0,0 +1,24 @@ +kritarcdir = $(kde_datadir)/kritaplugins +kritarc_DATA = histogram.rc + +EXTRA_DIST = $(kritarc_DATA) + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + -I../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = kritahistogram.la + +kritahistogram_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 = kritahistogram.desktop + +kritahistogram_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritahistogram_la_LIBADD = ../../../libkritacommon.la + +kritahistogram_la_METASOURCES = AUTO diff --git a/krita/plugins/viewplugins/histogram/dlg_histogram.cc b/krita/plugins/viewplugins/histogram/dlg_histogram.cc new file mode 100644 index 00000000..0440c9db --- /dev/null +++ b/krita/plugins/viewplugins/histogram/dlg_histogram.cc @@ -0,0 +1,68 @@ +/* + * dlg_histogram.cc - part of KimageShop^WKrayon^WKrita + * + * 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( QWidget * parent, const char * name) + : super (parent, 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->sizeHint()); +} + +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/krita/plugins/viewplugins/histogram/dlg_histogram.h b/krita/plugins/viewplugins/histogram/dlg_histogram.h new file mode 100644 index 00000000..790e77ef --- /dev/null +++ b/krita/plugins/viewplugins/histogram/dlg_histogram.h @@ -0,0 +1,57 @@ +/* + * dlg_histogram.h -- part of KimageShop^WKrayon^WKrita + * + * 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 + +public: + + DlgHistogram(QWidget * parent = 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/krita/plugins/viewplugins/histogram/histogram.cc b/krita/plugins/viewplugins/histogram/histogram.cc new file mode 100644 index 00000000..7db92dee --- /dev/null +++ b/krita/plugins/viewplugins/histogram/histogram.cc @@ -0,0 +1,105 @@ +/* + * histogram.h -- Part of Krita + * + * 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( kritahistogram, HistogramFactory( "krita" ) ) + +Histogram::Histogram(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + + if ( parent->inherits("KisView") ) { + + setInstance(HistogramFactory::instance()); + setXMLFile(locate("data","kritaplugins/histogram.rc"), true); + + m_action = new KAction(i18n("&Histogram"), 0, 0, this, SLOT(slotActivated()), actionCollection(), "histogram"); + + m_view = (KisView*) parent; + if (KisImageSP img = m_view->canvasSubject()->currentImg()) { + connect(img, SIGNAL(sigLayersChanged(KisGroupLayerSP)), this, SLOT(slotLayersChanged())); + connect(img, SIGNAL(sigLayerAdded(KisLayerSP)), this, SLOT(slotLayersChanged())); + connect(img, SIGNAL(sigLayerActivated(KisLayerSP)), this, SLOT(slotLayersChanged())); + connect(img, SIGNAL(sigLayerPropertiesChanged(KisLayerSP)), this, SLOT(slotLayersChanged())); + connect(img, SIGNAL(sigLayerRemoved(KisLayerSP, KisGroupLayerSP, KisLayerSP)), + this, SLOT(slotLayersChanged())); + connect(img, SIGNAL(sigLayerMoved(KisLayerSP, KisGroupLayerSP, KisLayerSP)), + this, 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() == QDialog::Accepted) { + // Do nothing; this is an informational dialog + } + delete dlgHistogram; +} + +#include "histogram.moc" + diff --git a/krita/plugins/viewplugins/histogram/histogram.h b/krita/plugins/viewplugins/histogram/histogram.h new file mode 100644 index 00000000..adaa6bfd --- /dev/null +++ b/krita/plugins/viewplugins/histogram/histogram.h @@ -0,0 +1,49 @@ +/* + * histogram.h -- Part of Krita + * + * 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 + public: + Histogram(QObject *parent, const char *name, const QStringList &); + 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/krita/plugins/viewplugins/histogram/histogram.rc b/krita/plugins/viewplugins/histogram/histogram.rc new file mode 100644 index 00000000..f41b50e7 --- /dev/null +++ b/krita/plugins/viewplugins/histogram/histogram.rc @@ -0,0 +1,10 @@ + + + + &Layer + + + + + + diff --git a/krita/plugins/viewplugins/histogram/kis_histogram_widget.cc b/krita/plugins/viewplugins/histogram/kis_histogram_widget.cc new file mode 100644 index 00000000..0e738435 --- /dev/null +++ b/krita/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(QWidget *parent, const char *name) + : super(parent, 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, SIGNAL(clicked(int)), this, SLOT(slotTypeSwitched(int))); + connect(cmbChannel, SIGNAL(activated(int)), this, SLOT(setActiveChannel(int))); + connect(zoomIn, SIGNAL(clicked()), this, SLOT(slotZoomIn())); + connect(zoomOut, SIGNAL(clicked()), this, SLOT(slotZoomOut())); + connect(currentView, SIGNAL(valueChanged(int)), this, 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/krita/plugins/viewplugins/histogram/kis_histogram_widget.h b/krita/plugins/viewplugins/histogram/kis_histogram_widget.h new file mode 100644 index 00000000..84b551d8 --- /dev/null +++ b/krita/plugins/viewplugins/histogram/kis_histogram_widget.h @@ -0,0 +1,54 @@ +/* + * 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 + +public: + KisHistogramWidget(QWidget *parent, 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/krita/plugins/viewplugins/histogram/kritahistogram.desktop b/krita/plugins/viewplugins/histogram/kritahistogram.desktop new file mode 100644 index 00000000..552f27d6 --- /dev/null +++ b/krita/plugins/viewplugins/histogram/kritahistogram.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=Krita/ViewPlugin +Type=Service +X-KDE-Library=kritahistogram +X-Krita-Version=2 diff --git a/krita/plugins/viewplugins/histogram/wdghistogram.ui b/krita/plugins/viewplugins/histogram/wdghistogram.ui new file mode 100644 index 00000000..e538adae --- /dev/null +++ b/krita/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 + + + + + + layout2 + + + + 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/krita/plugins/viewplugins/histogram_docker/Makefile.am b/krita/plugins/viewplugins/histogram_docker/Makefile.am new file mode 100644 index 00000000..6d116358 --- /dev/null +++ b/krita/plugins/viewplugins/histogram_docker/Makefile.am @@ -0,0 +1,21 @@ +kde_services_DATA = kritahistogramdocker.desktop +kritarcdir = $(kde_datadir)/kritaplugins +kritarc_DATA = kritahistogramdocker.rc + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kritahistogramdocker_la_SOURCES = histogramdocker.cc kis_imagerasteredcache.cc kis_cachedhistogram.cc kis_accumulating_producer.cc + +kde_module_LTLIBRARIES = kritahistogramdocker.la +noinst_HEADERS = histogramdocker.h kis_imagerasteredcache.h kis_cachedhistogram.h kis_accumulating_producer.h + +kritahistogramdocker_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritahistogramdocker_la_LIBADD = ../../../libkritacommon.la + +kritahistogramdocker_la_METASOURCES = AUTO diff --git a/krita/plugins/viewplugins/histogram_docker/histogramdocker.cc b/krita/plugins/viewplugins/histogram_docker/histogramdocker.cc new file mode 100644 index 00000000..93d77bfb --- /dev/null +++ b/krita/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 KritaHistogramDockerFactory; +K_EXPORT_COMPONENT_FACTORY( kritahistogramdocker, KritaHistogramDockerFactory( "krita" ) ) + +KritaHistogramDocker::KritaHistogramDocker(QObject *parent, const char *name, const QStringList&) + : KParts::Plugin(parent, name) +{ + + if ( parent->inherits("KisView") ) { + m_view = dynamic_cast(parent); + + setInstance(KritaHistogramDockerFactory::instance()); + setXMLFile(locate("data","kritaplugins/kritahistogramdocker.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); + QToolTip::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, SIGNAL(rightClicked(const QPoint&)), + this, SLOT(popupMenu(const QPoint&))); + connect(m_cache, SIGNAL(cacheUpdated()), + new HistogramDockerUpdater(this, m_histogram, m_hview, m_producer), SLOT(updated())); + connect(&m_popup, SIGNAL(activated(int)), + this, SLOT(producerChanged(int))); + connect(img, SIGNAL(sigColorSpaceChanged(KisColorSpace*)), + this, SLOT(colorSpaceChanged(KisColorSpace*))); // No need to force updates here + + // Add it to the control palette + m_view->canvasSubject()->paletteManager()->addWidget( + m_hview, "histodocker", krita::CONTROL_PALETTE); + } else { + m_cache = 0; + } +} + +KritaHistogramDocker::~KritaHistogramDocker() +{ + uint count = m_producers . count(); + for (uint i = 0; i < count; i++) { + delete m_producers . at(i); + } + + if (m_cache) + m_cache->deleteLater(); +} + +void KritaHistogramDocker::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, SIGNAL(cacheUpdated()), + new HistogramDockerUpdater(this, m_histogram, m_hview, m_producer), SLOT(updated())); + } +} + +void KritaHistogramDocker::popupMenu(const QPoint& pos) +{ + m_popup.popup(pos, m_currentProducerPos); +} + +void KritaHistogramDocker::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(QObject* /*parent*/, KisHistogramSP h, KisHistogramView* v, + KisAccumulatingHistogramProducer* p) + : m_histogram(h), m_view(v), m_producer(p) +{ + connect(p, SIGNAL(completed()), this, 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/krita/plugins/viewplugins/histogram_docker/histogramdocker.h b/krita/plugins/viewplugins/histogram_docker/histogramdocker.h new file mode 100644 index 00000000..5cc57e18 --- /dev/null +++ b/krita/plugins/viewplugins/histogram_docker/histogramdocker.h @@ -0,0 +1,79 @@ +/* + * This file is part of Krita + * + * 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 KritaHistogramDocker : public KParts::Plugin +{ +Q_OBJECT +public: + KritaHistogramDocker(QObject *parent, const char *name, const QStringList &); + virtual ~KritaHistogramDocker(); +private slots: + void producerChanged(int pos); + void popupMenu(const QPoint & 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; + QPopupMenu m_popup; + KisHistogramSP m_histogram; + uint m_currentProducerPos; +}; + +class KisGenericRGBHistogramProducerFactory; + +class HistogramDockerUpdater : public QObject { +Q_OBJECT +public: + HistogramDockerUpdater(QObject* parent, 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/krita/plugins/viewplugins/histogram_docker/kis_accumulating_producer.cc b/krita/plugins/viewplugins/histogram_docker/kis_accumulating_producer.cc new file mode 100644 index 00000000..f899f2af --- /dev/null +++ b/krita/plugins/viewplugins/histogram_docker/kis_accumulating_producer.cc @@ -0,0 +1,102 @@ +/* + * This file is part of Krita + * + * 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 = QEvent::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 QThread { + 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; + QValueVector& 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 + QApplication::postEvent(m_source, new QCustomEvent(EmitCompletedType)); + } +} + +void KisAccumulatingHistogramProducer::customEvent(QCustomEvent* e) { + if (e->type() == EmitCompletedType) { + emit completed(); + } +} + +#include "kis_accumulating_producer.moc" + diff --git a/krita/plugins/viewplugins/histogram_docker/kis_accumulating_producer.h b/krita/plugins/viewplugins/histogram_docker/kis_accumulating_producer.h new file mode 100644 index 00000000..4ef9f02a --- /dev/null +++ b/krita/plugins/viewplugins/histogram_docker/kis_accumulating_producer.h @@ -0,0 +1,76 @@ +/* + * This file is part of Krita + * + * 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 QObject, public KisBasicHistogramProducer { +Q_OBJECT +public: + KisAccumulatingHistogramProducer(KisCachedHistogramObserver::Producers* source); + ~KisAccumulatingHistogramProducer(); + /// Does _nothing_, use addRegionsToBinAsync + virtual void addRegionToBin(Q_UINT8 *, Q_UINT8*, Q_UINT32, KisColorSpace *) {} + virtual void addRegionsToBinAsync(); + virtual QString 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 Q_INT32 numberOfBins() { return m_source->at(0)->numberOfBins(); } + + virtual QValueVector 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(QCustomEvent* 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/krita/plugins/viewplugins/histogram_docker/kis_cachedhistogram.cc b/krita/plugins/viewplugins/histogram_docker/kis_cachedhistogram.cc new file mode 100644 index 00000000..2b0c9b85 --- /dev/null +++ b/krita/plugins/viewplugins/histogram_docker/kis_cachedhistogram.cc @@ -0,0 +1,37 @@ +/* + * This file is part of Krita + * + * 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/krita/plugins/viewplugins/histogram_docker/kis_cachedhistogram.h b/krita/plugins/viewplugins/histogram_docker/kis_cachedhistogram.h new file mode 100644 index 00000000..dfe7a05e --- /dev/null +++ b/krita/plugins/viewplugins/histogram_docker/kis_cachedhistogram.h @@ -0,0 +1,53 @@ +/* + * This file is part of Krita + * + * 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 QValueVector 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/krita/plugins/viewplugins/histogram_docker/kis_imagerasteredcache.cc b/krita/plugins/viewplugins/histogram_docker/kis_imagerasteredcache.cc new file mode 100644 index 00000000..2c6562df --- /dev/null +++ b/krita/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, SIGNAL(sigImageUpdated(QRect)), + this, SLOT(imageUpdated(QRect))); + connect(img, SIGNAL(sigSizeChanged(Q_INT32, Q_INT32)), + this, SLOT(imageSizeChanged(Q_INT32, Q_INT32))); + connect(&m_timer, SIGNAL(timeout()), this, SLOT(timeOut())); +} + +KisImageRasteredCache::~KisImageRasteredCache() { + cleanUpElements(); +} + +void KisImageRasteredCache::imageUpdated(QRect rc) { + + if (rc.isValid()) { + QRect 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(Q_INT32 w, Q_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(QRect(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()) { + QTimer::singleShot(0, this, 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/krita/plugins/viewplugins/histogram_docker/kis_imagerasteredcache.h b/krita/plugins/viewplugins/histogram_docker/kis_imagerasteredcache.h new file mode 100644 index 00000000..6335eadb --- /dev/null +++ b/krita/plugins/viewplugins/histogram_docker/kis_imagerasteredcache.h @@ -0,0 +1,80 @@ +/* + * 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 QObject { +Q_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(QRect rc); + void imageSizeChanged(Q_INT32 w, Q_INT32 h); + void timeOut(); + +private: + class Element { + public: + Element(Observer* o) : observer(o), valid(true) {} + Observer* observer; + bool valid; + }; + typedef QValueVector< QValueVector > Raster; + typedef QValueList Queue; + + void cleanUpElements(); + + Observer* m_observer; + Raster m_raster; + Queue m_queue; + QTimer 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/krita/plugins/viewplugins/histogram_docker/kritahistogramdocker.desktop b/krita/plugins/viewplugins/histogram_docker/kritahistogramdocker.desktop new file mode 100644 index 00000000..1603058d --- /dev/null +++ b/krita/plugins/viewplugins/histogram_docker/kritahistogramdocker.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=Krita/ViewPlugin +Type=Service +X-KDE-Library=kritahistogramdocker +X-Krita-Version=2 diff --git a/krita/plugins/viewplugins/histogram_docker/kritahistogramdocker.rc b/krita/plugins/viewplugins/histogram_docker/kritahistogramdocker.rc new file mode 100644 index 00000000..525fd65b --- /dev/null +++ b/krita/plugins/viewplugins/histogram_docker/kritahistogramdocker.rc @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/krita/plugins/viewplugins/history_docker/Makefile.am b/krita/plugins/viewplugins/history_docker/Makefile.am new file mode 100644 index 00000000..0432d54d --- /dev/null +++ b/krita/plugins/viewplugins/history_docker/Makefile.am @@ -0,0 +1,18 @@ +#kde_services_DATA = kritahistorydocker.desktop + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kritahistorydocker_la_SOURCES = historydocker.cc + +kde_module_LTLIBRARIES = kritahistorydocker.la +noinst_HEADERS = historydocker.h + +kritahistorydocker_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritahistorydocker_la_LIBADD = ../../../libkritacommon.la + +kritahistorydocker_la_METASOURCES = AUTO diff --git a/krita/plugins/viewplugins/history_docker/historydocker.cc b/krita/plugins/viewplugins/history_docker/historydocker.cc new file mode 100644 index 00000000..20b1d013 --- /dev/null +++ b/krita/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 KritaHistoryDockerFactory; +K_EXPORT_COMPONENT_FACTORY( kritahistorydocker, KritaHistoryDockerFactory( "krita" ) ) + +KritaHistoryDocker::KritaHistoryDocker(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + + + + if ( parent->inherits("KisView") ) + { + setInstance(KritaHistoryDockerFactory::instance()); + // Create history docker + // Add the docker to the docker manager + // Connect the undo system to the docker + } + +} + +KritaHistoryDocker::~KritaHistoryDocker() +{ +} diff --git a/krita/plugins/viewplugins/history_docker/historydocker.h b/krita/plugins/viewplugins/history_docker/historydocker.h new file mode 100644 index 00000000..8556d37c --- /dev/null +++ b/krita/plugins/viewplugins/history_docker/historydocker.h @@ -0,0 +1,34 @@ +/* + * This file is part of Krita + * + * 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 KritaHistoryDocker : public KParts::Plugin +{ +public: + KritaHistoryDocker(QObject *parent, const char *name, const QStringList &); + virtual ~KritaHistoryDocker(); +}; + + +#endif //_HISTORYDOCKER_H diff --git a/krita/plugins/viewplugins/history_docker/kritahistorydocker.desktop b/krita/plugins/viewplugins/history_docker/kritahistorydocker.desktop new file mode 100644 index 00000000..52d5e40a --- /dev/null +++ b/krita/plugins/viewplugins/history_docker/kritahistorydocker.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 Krita +Comment[bg]=Основната функционалност на Krita +Comment[ca]=Amarrador d'història d'ordres per a Krita +Comment[cy]=Bachydd yr hanes gorchmynion ar gyfer Krita +Comment[da]=Dokning af kommandohistorik for Krita +Comment[de]=Befehlsverlauf-Docker für Krita +Comment[el]=Άρθρωμα προσάρτησης ιστορικού εντολών για το Krita +Comment[es]=Anclaje con el histórico de órdenes para Krita +Comment[et]=Krita käskude ajaloo dokk +Comment[fa]=پیونددهنده تاریخچۀ فرمان برای Krita +Comment[fr]=Ancrage de l'historique des commandes pour Krita +Comment[fy]=Komponint mei bewurkingshistoarje foar Krita" +Comment[gl]=Un módulo acoplado co historial de comandos para Krita +Comment[hu]=Krita parancselőzmény-dokkoló +Comment[is]=Skipanasöguspjald fyrir Krita +Comment[it]=Aggancia-cronologia dei comandi di Krita +Comment[ja]=Krita コマンド履歴ドックパネル +Comment[km]=កន្លែង​ចត​ប្រវត្តិ​ពាក្យបញ្ជា​សម្រាប់ Krita +Comment[nb]=Kommandohistorie-dokker for Krita +Comment[nds]=Befehlsvörgeschicht-Docker för Krita +Comment[ne]=क्रिताका लागि आदेश इतिहास +Comment[nl]=Component met bewerkingsgeschiedenis voor Krita +Comment[pl]=Doker historii poleceń dla Krita +Comment[pt]=Um módulo acoplado de histórico de comandos do Krita +Comment[pt_BR]=Um módulo acoplado de histórico de comandos do Krita +Comment[ru]=Панель истории команд Krita +Comment[sk]=História príkazov pre Krita +Comment[sl]=Zgodovina ukazov za Krito +Comment[sr]=Сидраш историјата наредби за Krita-у +Comment[sr@Latn]=Sidraš istorijata naredbi za Krita-u +Comment[sv]=Dockning av kommandohistorik för Krita +Comment[uk]=Швартувальник історії команд для Krita +Comment[uz]=Krita uchun buyruqlar tarixi paneli +Comment[uz@cyrillic]=Krita учун буйруқлар тарихи панели +Comment[zh_TW]=Krita 的指令紀錄停駐點 +ServiceTypes=Krita/ViewPlugin +Type=Service +X-KDE-Library=kritahistorydocker +X-Krita-Version=2 diff --git a/krita/plugins/viewplugins/imagesize/Makefile.am b/krita/plugins/viewplugins/imagesize/Makefile.am new file mode 100644 index 00000000..12cd96bb --- /dev/null +++ b/krita/plugins/viewplugins/imagesize/Makefile.am @@ -0,0 +1,24 @@ +kritarcdir = $(kde_datadir)/kritaplugins +kritarc_DATA = imagesize.rc +EXTRA_DIST = $(kritarc_DATA) + +kde_services_DATA = kritaimagesize.desktop + + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kritaimagesize_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 = kritaimagesize.la + +kritaimagesize_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritaimagesize_la_LIBADD = ../../../libkritacommon.la + +kritaimagesize_la_METASOURCES = AUTO diff --git a/krita/plugins/viewplugins/imagesize/configure.in.in b/krita/plugins/viewplugins/imagesize/configure.in.in new file mode 100644 index 00000000..0875ce32 --- /dev/null +++ b/krita/plugins/viewplugins/imagesize/configure.in.in @@ -0,0 +1 @@ +AC_CHECK_DECLS([round], [], [], [#include ]) diff --git a/krita/plugins/viewplugins/imagesize/dlg_imagesize.cc b/krita/plugins/viewplugins/imagesize/dlg_imagesize.cc new file mode 100644 index 00000000..9a641b94 --- /dev/null +++ b/krita/plugins/viewplugins/imagesize/dlg_imagesize.cc @@ -0,0 +1,277 @@ +/* + * dlg_imagesize.cc - part of KimageShop^WKrayon^WKrita + * + * 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( QWidget * parent, + const char * name) + : super (parent, 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->sizeHint()); + + unblockAll(); + + + connect(this, SIGNAL(okClicked()), + this, SLOT(okClicked())); + +} + +DlgImageSize::~DlgImageSize() +{ + delete m_page; +} + +void DlgImageSize::hideScaleBox() +{ + m_page->grpResizeScale->hide(); +} + +void DlgImageSize::setWidth(Q_UINT32 w) +{ + blockAll(); + + m_page->lblWidthOriginal->setNum((int)w); + m_page->intWidth->setValue(w); + m_oldW = w; + m_origW = w; + + unblockAll(); +} + +void DlgImageSize::setWidthPercent(Q_UINT32 w) +{ + blockAll(); + + m_page->intWidthPercent->setValue(w); + m_oldWPercent = w; + + unblockAll(); +} + + +void DlgImageSize::setMaximumWidth(Q_UINT32 w) +{ + m_page->intWidth->setMaxValue(w); + m_maxW = w; +} + +Q_INT32 DlgImageSize::width() +{ + //return (Q_INT32)qRound(m_oldW); + return (Q_INT32)qRound(m_page->intWidth->value()); +} + +void DlgImageSize::setHeight(Q_UINT32 h) +{ + blockAll(); + + m_page->lblHeightOriginal->setNum((int)h); + m_page->intHeight->setValue(h); + m_oldH = h; + m_origH = h; + + unblockAll(); +} + + +void DlgImageSize::setHeightPercent(Q_UINT32 h) +{ + blockAll(); + + m_page->intHeightPercent->setValue(h); + m_oldHPercent = h; + + unblockAll(); +} + + + +void DlgImageSize::setMaximumHeight(Q_UINT32 h) +{ + m_page->intHeight->setMaxValue(h); + m_maxH = h; +} + + +Q_INT32 DlgImageSize::height() +{ + //return (Q_INT32)qRound(m_oldH); + return (Q_INT32)qRound(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(qRound(wPercent)); + + // Set height in pixels and percent of necessary + if (m_page->chkConstrain->isChecked()) { + m_page->intHeightPercent->setValue(qRound(wPercent)); + + m_oldH = qRound(m_origH * wPercent / 100); + m_page->intHeight->setValue(qRound(m_oldH)); + + } + m_oldW = w; + + unblockAll(); +} + +void DlgImageSize::slotHeightPixelsChanged(int h) +{ + blockAll(); + + double hPercent = double(h) * 100 / double(m_origH); + + m_page->intHeightPercent->setValue(qRound(hPercent)); + + // Set width in pixels and percent of necessary + if (m_page->chkConstrain->isChecked()) { + m_page->intWidthPercent->setValue(qRound(hPercent)); + + m_oldW = qRound(m_origW * hPercent / 100); + m_page->intWidth->setValue(qRound(m_oldW)); + + } + m_oldH = h; + + unblockAll(); +} + +void DlgImageSize::slotWidthPercentChanged(int w) +{ + blockAll(); + + m_page->intWidth->setValue(qRound(w * m_origW / 100)); + + if (m_page->chkConstrain->isChecked()) { + m_page->intHeightPercent->setValue(w); + m_page->intHeight->setValue(qRound( w * m_origH / 100)); + } + + unblockAll(); +} + +void DlgImageSize::slotHeightPercentChanged(int h) +{ + blockAll(); + + m_page->intHeight->setValue(qRound(h * m_origH / 100)); + if (m_page->chkConstrain->isChecked()) { + m_page->intWidthPercent->setValue(h); + m_page->intWidth->setValue(qRound( 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, SIGNAL(valueChanged(int)), + this, SLOT(slotWidthPixelsChanged(int))); + + connect (m_page->intHeight, SIGNAL(valueChanged(int)), + this, SLOT(slotHeightPixelsChanged(int))); + + connect (m_page->intWidthPercent, SIGNAL(valueChanged(int)), + this, SLOT(slotWidthPercentChanged(int))); + + connect (m_page->intHeightPercent, SIGNAL(valueChanged(int)), + this, SLOT(slotHeightPercentChanged(int))); + + +} + +#include "dlg_imagesize.moc" diff --git a/krita/plugins/viewplugins/imagesize/dlg_imagesize.h b/krita/plugins/viewplugins/imagesize/dlg_imagesize.h new file mode 100644 index 00000000..169d8cbd --- /dev/null +++ b/krita/plugins/viewplugins/imagesize/dlg_imagesize.h @@ -0,0 +1,82 @@ +/* + * dlg_imagesize.h -- part of KimageShop^WKrayon^WKrita + * + * 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 mask based + * on a (range of) colors. + */ +class DlgImageSize: public KDialogBase { + typedef KDialogBase super; + Q_OBJECT + +public: + + DlgImageSize(QWidget * parent = 0, + const char* name = 0); + ~DlgImageSize(); + + void hideScaleBox(); + + void setWidth(Q_UINT32 w); + void setWidthPercent(Q_UINT32 w); + void setMaximumWidth(Q_UINT32 w); + Q_INT32 width(); + + void setHeight(Q_UINT32 h); + void setHeightPercent(Q_UINT32 h); + void setMaximumHeight(Q_UINT32 h); + Q_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/krita/plugins/viewplugins/imagesize/dlg_layersize.cc b/krita/plugins/viewplugins/imagesize/dlg_layersize.cc new file mode 100644 index 00000000..ba942eca --- /dev/null +++ b/krita/plugins/viewplugins/imagesize/dlg_layersize.cc @@ -0,0 +1,261 @@ +/* + * dlg_layersize.cc - part of Krita + * + * 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( QWidget * parent, + const char * name) + : super (parent, 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->sizeHint()); + + unblockAll(); + + + connect(this, SIGNAL(okClicked()), + this, SLOT(okClicked())); + +} + +DlgLayerSize::~DlgLayerSize() +{ + delete m_page; +} + +void DlgLayerSize::setWidth(Q_UINT32 w) +{ + blockAll(); + + m_page->lblWidthOriginal->setNum((int)w); + m_page->intWidth->setValue(w); + m_oldW = w; + m_origW = w; + + unblockAll(); +} + +void DlgLayerSize::setWidthPercent(Q_UINT32 w) +{ + blockAll(); + + m_page->intWidthPercent->setValue(w); + m_oldWPercent = w; + + unblockAll(); +} + + +void DlgLayerSize::setMaximumWidth(Q_UINT32 w) +{ + m_page->intWidth->setMaxValue(w); + m_maxW = w; +} + +Q_INT32 DlgLayerSize::width() +{ + //return (Q_INT32)qRound(m_oldW); + return (Q_INT32)qRound(m_page->intWidth->value()); +} + +void DlgLayerSize::setHeight(Q_UINT32 h) +{ + blockAll(); + + m_page->lblHeightOriginal->setNum((int)h); + m_page->intHeight->setValue(h); + m_oldH = h; + m_origH = h; + + unblockAll(); +} + + +void DlgLayerSize::setHeightPercent(Q_UINT32 h) +{ + blockAll(); + + m_page->intHeightPercent->setValue(h); + m_oldHPercent = h; + + unblockAll(); +} + +void DlgLayerSize::setMaximumHeight(Q_UINT32 h) +{ + m_page->intHeight->setMaxValue(h); + m_maxH = h; +} + +Q_INT32 DlgLayerSize::height() +{ + //return (Q_INT32)qRound(m_oldH); + return (Q_INT32)qRound(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(qRound(wPercent)); + + // Set height in pixels and percent of necessary + if (m_page->chkConstrain->isChecked()) { + m_page->intHeightPercent->setValue(qRound(wPercent)); + + m_oldH = qRound(m_origH * wPercent / 100); + m_page->intHeight->setValue(qRound(m_oldH)); + + } + m_oldW = w; + + unblockAll(); +} + +void DlgLayerSize::slotHeightPixelsChanged(int h) +{ + blockAll(); + + double hPercent = double(h) * 100 / double(m_origH); + + m_page->intHeightPercent->setValue(qRound(hPercent)); + + // Set width in pixels and percent of necessary + if (m_page->chkConstrain->isChecked()) { + m_page->intWidthPercent->setValue(qRound(hPercent)); + + m_oldW = qRound(m_origW * hPercent / 100); + m_page->intWidth->setValue(qRound(m_oldW)); + + } + m_oldH = h; + + unblockAll(); +} + +void DlgLayerSize::slotWidthPercentChanged(int w) +{ + blockAll(); + + m_page->intWidth->setValue(qRound(w * m_origW / 100)); + + if (m_page->chkConstrain->isChecked()) { + m_page->intHeightPercent->setValue(w); + m_page->intHeight->setValue(qRound( w * m_origH / 100)); + } + + unblockAll(); +} + +void DlgLayerSize::slotHeightPercentChanged(int h) +{ + blockAll(); + + m_page->intHeight->setValue(qRound(h * m_origH / 100)); + if (m_page->chkConstrain->isChecked()) { + m_page->intWidthPercent->setValue(h); + m_page->intWidth->setValue(qRound( 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, SIGNAL(valueChanged(int)), + this, SLOT(slotWidthPixelsChanged(int))); + + connect (m_page->intHeight, SIGNAL(valueChanged(int)), + this, SLOT(slotHeightPixelsChanged(int))); + + connect (m_page->intWidthPercent, SIGNAL(valueChanged(int)), + this, SLOT(slotWidthPercentChanged(int))); + + connect (m_page->intHeightPercent, SIGNAL(valueChanged(int)), + this, SLOT(slotHeightPercentChanged(int))); + + +} + +#include "dlg_layersize.moc" diff --git a/krita/plugins/viewplugins/imagesize/dlg_layersize.h b/krita/plugins/viewplugins/imagesize/dlg_layersize.h new file mode 100644 index 00000000..fa27b732 --- /dev/null +++ b/krita/plugins/viewplugins/imagesize/dlg_layersize.h @@ -0,0 +1,73 @@ +/* + * dlg_layersize.h -- part of Krita + * + * 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 + +public: + + DlgLayerSize(QWidget * parent = 0, + const char* name = 0); + ~DlgLayerSize(); + + void setWidth(Q_UINT32 w); + void setWidthPercent(Q_UINT32 w); + void setMaximumWidth(Q_UINT32 w); + Q_INT32 width(); + + void setHeight(Q_UINT32 h); + void setHeightPercent(Q_UINT32 h); + void setMaximumHeight(Q_UINT32 h); + Q_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/krita/plugins/viewplugins/imagesize/imagesize.cc b/krita/plugins/viewplugins/imagesize/imagesize.cc new file mode 100644 index 00000000..df400b5a --- /dev/null +++ b/krita/plugins/viewplugins/imagesize/imagesize.cc @@ -0,0 +1,190 @@ +/* + * imagesize.cc -- Part of Krita + * + * 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( kritaimagesize, ImageSizeFactory( "krita" ) ) + +ImageSize::ImageSize(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + if ( parent->inherits("KisView") ) + { + setInstance(ImageSizeFactory::instance()); + setXMLFile(locate("data","kritaplugins/imagesize.rc"), true); + + (void) new KAction(i18n("Change &Image Size..."), 0, "Shift-s", this, SLOT(slotImageSize()), actionCollection(), "imagesize"); + (void) new KAction(i18n("&Scale Layer..."), 0, 0, this, SLOT(slotLayerSize()), actionCollection(), "layerscale"); + + + m_view = (KisView*) parent; + // Selection manager takes ownership? + KAction * a = new KAction(i18n("&Scale Selection..."), 0, 0, this, 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() == QDialog::Accepted) { + Q_INT32 w = dlgImageSize->width(); + Q_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(); + + QRect rc = dev->exactBounds(); + + dlgLayerSize->setWidth(rc.width()); + dlgLayerSize->setHeight(rc.height()); + + if (dlgLayerSize->exec() == QDialog::Accepted) { + Q_INT32 w = dlgLayerSize->width(); + Q_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; + QRect rc = layer->selection()->selectedRect(); + + dlgLayerSize->setWidth(rc.width()); + dlgLayerSize->setHeight(rc.height()); + + if (dlgLayerSize->exec() == QDialog::Accepted) { + Q_INT32 w = dlgLayerSize->width(); + Q_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/krita/plugins/viewplugins/imagesize/imagesize.h b/krita/plugins/viewplugins/imagesize/imagesize.h new file mode 100644 index 00000000..ce8f0f41 --- /dev/null +++ b/krita/plugins/viewplugins/imagesize/imagesize.h @@ -0,0 +1,48 @@ +/* + * imagesize.h -- Part of Krita + * + * 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 +public: + ImageSize(QObject *parent, const char *name, const QStringList &); + virtual ~ImageSize(); + +private slots: + + void slotImageSize(); + void slotLayerSize(); + void slotSelectionScale(); + +private: + + KisView * m_view; + KisPainter * m_painter; + +}; + +#endif // IMAGESIZE_H diff --git a/krita/plugins/viewplugins/imagesize/imagesize.rc b/krita/plugins/viewplugins/imagesize/imagesize.rc new file mode 100644 index 00000000..8b7e12c9 --- /dev/null +++ b/krita/plugins/viewplugins/imagesize/imagesize.rc @@ -0,0 +1,15 @@ + + + + Image + + + + Layer + + + &Select + + + + diff --git a/krita/plugins/viewplugins/imagesize/kritaimagesize.desktop b/krita/plugins/viewplugins/imagesize/kritaimagesize.desktop new file mode 100644 index 00000000..edf202f4 --- /dev/null +++ b/krita/plugins/viewplugins/imagesize/kritaimagesize.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=Krita/ViewPlugin +Type=Service +X-KDE-Library=kritaimagesize +X-Krita-Version=2 diff --git a/krita/plugins/viewplugins/imagesize/wdg_imagesize.ui b/krita/plugins/viewplugins/imagesize/wdg_imagesize.ui new file mode 100644 index 00000000..896bbb05 --- /dev/null +++ b/krita/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/krita/plugins/viewplugins/imagesize/wdg_layersize.ui b/krita/plugins/viewplugins/imagesize/wdg_layersize.ui new file mode 100644 index 00000000..1b642fd8 --- /dev/null +++ b/krita/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/krita/plugins/viewplugins/imagesize/wdg_resolution.ui b/krita/plugins/viewplugins/imagesize/wdg_resolution.ui new file mode 100644 index 00000000..ead01819 --- /dev/null +++ b/krita/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/krita/plugins/viewplugins/modify_selection/Makefile.am b/krita/plugins/viewplugins/modify_selection/Makefile.am new file mode 100644 index 00000000..f70b7cf2 --- /dev/null +++ b/krita/plugins/viewplugins/modify_selection/Makefile.am @@ -0,0 +1,26 @@ +kritarcdir = $(kde_datadir)/kritaplugins +kritarc_DATA = modify_selection.rc +EXTRA_DIST = $(kritarc_DATA) + +kde_services_DATA = kritamodifyselection.desktop + + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kritamodifyselection_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 = kritamodifyselection.la + +kritamodifyselection_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritamodifyselection_la_LIBADD = ../../../libkritacommon.la + +kritamodifyselection_la_METASOURCES = AUTO diff --git a/krita/plugins/viewplugins/modify_selection/dlg_border_selection.cc b/krita/plugins/viewplugins/modify_selection/dlg_border_selection.cc new file mode 100644 index 00000000..748c5b9b --- /dev/null +++ b/krita/plugins/viewplugins/modify_selection/dlg_border_selection.cc @@ -0,0 +1,76 @@ +/* + * dlg_border_selection.cc - part of Krita + * + * 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( QWidget * parent, const char * name) : super (parent, 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->sizeHint()); + + connect(this, SIGNAL(okClicked()), this, SLOT(okClicked())); +} + +DlgBorderSelection::~DlgBorderSelection() +{ + delete m_page; +} + +Q_INT32 DlgBorderSelection::xradius() +{ + return m_page->radiusSpinBox->value(); +} + +Q_INT32 DlgBorderSelection::yradius() +{ + return m_page->radiusSpinBox->value(); +} + + +// SLOTS + +void DlgBorderSelection::okClicked() +{ + accept(); +} + +#include "dlg_border_selection.moc" diff --git a/krita/plugins/viewplugins/modify_selection/dlg_border_selection.h b/krita/plugins/viewplugins/modify_selection/dlg_border_selection.h new file mode 100644 index 00000000..baf716d4 --- /dev/null +++ b/krita/plugins/viewplugins/modify_selection/dlg_border_selection.h @@ -0,0 +1,48 @@ +/* + * dlg_border_selection.h -- part of Krita + * + * 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 + +public: + + DlgBorderSelection(QWidget * parent = 0, const char* name = 0); + ~DlgBorderSelection(); + + Q_INT32 xradius(); + Q_INT32 yradius(); + +private slots: + + void okClicked(); + +private: + + WdgBorderSelection * m_page; +}; + +#endif // DLG_BORDER_SELECTION_H diff --git a/krita/plugins/viewplugins/modify_selection/dlg_grow_selection.cc b/krita/plugins/viewplugins/modify_selection/dlg_grow_selection.cc new file mode 100644 index 00000000..82055aeb --- /dev/null +++ b/krita/plugins/viewplugins/modify_selection/dlg_grow_selection.cc @@ -0,0 +1,76 @@ +/* + * dlg_grow_selection.cc - part of Krita + * + * 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( QWidget * parent, const char * name) : super (parent, 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->sizeHint()); + + connect(this, SIGNAL(okClicked()), this, SLOT(okClicked())); +} + +DlgGrowSelection::~DlgGrowSelection() +{ + delete m_page; +} + +Q_INT32 DlgGrowSelection::xradius() +{ + return m_page->radiusSpinBox->value(); +} + +Q_INT32 DlgGrowSelection::yradius() +{ + return m_page->radiusSpinBox->value(); +} + + +// SLOTS + +void DlgGrowSelection::okClicked() +{ + accept(); +} + +#include "dlg_grow_selection.moc" diff --git a/krita/plugins/viewplugins/modify_selection/dlg_grow_selection.h b/krita/plugins/viewplugins/modify_selection/dlg_grow_selection.h new file mode 100644 index 00000000..f5cd36ff --- /dev/null +++ b/krita/plugins/viewplugins/modify_selection/dlg_grow_selection.h @@ -0,0 +1,48 @@ +/* + * dlg_grow_selection.h -- part of Krita + * + * 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 + +public: + + DlgGrowSelection(QWidget * parent = 0, const char* name = 0); + ~DlgGrowSelection(); + + Q_INT32 xradius(); + Q_INT32 yradius(); + +private slots: + + void okClicked(); + +private: + + WdgGrowSelection * m_page; +}; + +#endif // DLG_GROW_SELECTION_H diff --git a/krita/plugins/viewplugins/modify_selection/dlg_shrink_selection.cc b/krita/plugins/viewplugins/modify_selection/dlg_shrink_selection.cc new file mode 100644 index 00000000..69e31d1d --- /dev/null +++ b/krita/plugins/viewplugins/modify_selection/dlg_shrink_selection.cc @@ -0,0 +1,81 @@ +/* + * dlg_shrink_selection.cc - part of Krita + * + * 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( QWidget * parent, const char * name) : super (parent, 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->sizeHint()); + + connect(this, SIGNAL(okClicked()), this, SLOT(okClicked())); +} + +DlgShrinkSelection::~DlgShrinkSelection() +{ + delete m_page; +} + +Q_INT32 DlgShrinkSelection::xradius() +{ + return m_page->radiusSpinBox->value(); +} + +Q_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/krita/plugins/viewplugins/modify_selection/dlg_shrink_selection.h b/krita/plugins/viewplugins/modify_selection/dlg_shrink_selection.h new file mode 100644 index 00000000..e8e32f43 --- /dev/null +++ b/krita/plugins/viewplugins/modify_selection/dlg_shrink_selection.h @@ -0,0 +1,49 @@ +/* + * dlg_shrink_selection.h -- part of Krita + * + * 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 + +public: + + DlgShrinkSelection(QWidget * parent = 0, const char* name = 0); + ~DlgShrinkSelection(); + + Q_INT32 xradius(); + Q_INT32 yradius(); + bool shrinkFromImageBorder(); + +private slots: + + void okClicked(); + +private: + + WdgShrinkSelection * m_page; +}; + +#endif // DLG_SHRINK_SELECTION_H diff --git a/krita/plugins/viewplugins/modify_selection/kritamodifyselection.desktop b/krita/plugins/viewplugins/modify_selection/kritamodifyselection.desktop new file mode 100644 index 00000000..cc3acc48 --- /dev/null +++ b/krita/plugins/viewplugins/modify_selection/kritamodifyselection.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=Krita/ViewPlugin +Type=Service +X-KDE-Library=kritamodifyselection +X-Krita-Version=2 diff --git a/krita/plugins/viewplugins/modify_selection/modify_selection.cc b/krita/plugins/viewplugins/modify_selection/modify_selection.cc new file mode 100644 index 00000000..6f2d0511 --- /dev/null +++ b/krita/plugins/viewplugins/modify_selection/modify_selection.cc @@ -0,0 +1,158 @@ +/* + * modify_selection.cc -- Part of Krita + * + * 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( kritamodifyselection, ModifySelectionFactory( "krita" ) ) + +ModifySelection::ModifySelection(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + if ( parent->inherits("KisView") ) + { + setInstance(ModifySelectionFactory::instance()); + setXMLFile(locate("data","kritaplugins/modify_selection.rc"), true); + + m_view = (KisView*) parent; + + // Selection manager takes ownership? + KAction* a = new KAction(i18n("Grow Selection..."), 0, 0, this, SLOT(slotGrowSelection()), actionCollection(), "growselection"); + KAction* b = new KAction(i18n("Shrink Selection..."), 0, 0, this, SLOT(slotShrinkSelection()), actionCollection(), "shrinkselection"); + KAction* c = new KAction(i18n("Border Selection..."), 0, 0, this, 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() == QDialog::Accepted) { + Q_INT32 xradius = dlgGrowSelection->xradius(); + Q_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() == QDialog::Accepted) { + Q_INT32 xradius = dlgShrinkSelection->xradius(); + Q_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() == QDialog::Accepted) { + Q_INT32 xradius = dlgBorderSelection->xradius(); + Q_INT32 yradius = dlgBorderSelection->yradius(); + + m_view ->canvasSubject()-> selectionManager()->border(xradius, yradius); + } + + delete dlgBorderSelection; +} + +#include "modify_selection.moc" diff --git a/krita/plugins/viewplugins/modify_selection/modify_selection.h b/krita/plugins/viewplugins/modify_selection/modify_selection.h new file mode 100644 index 00000000..d3677088 --- /dev/null +++ b/krita/plugins/viewplugins/modify_selection/modify_selection.h @@ -0,0 +1,46 @@ +/* + * modify_selection.h -- Part of Krita + * + * 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 +public: + ModifySelection(QObject *parent, const char *name, const QStringList &); + virtual ~ModifySelection(); + +private slots: + + void slotGrowSelection(); + void slotShrinkSelection(); + void slotBorderSelection(); + +private: + + KisView * m_view; + +}; + +#endif // MODIFY_SELECTION_H diff --git a/krita/plugins/viewplugins/modify_selection/modify_selection.rc b/krita/plugins/viewplugins/modify_selection/modify_selection.rc new file mode 100644 index 00000000..131534e3 --- /dev/null +++ b/krita/plugins/viewplugins/modify_selection/modify_selection.rc @@ -0,0 +1,10 @@ + + + + &Select + + + + + + diff --git a/krita/plugins/viewplugins/modify_selection/wdg_border_selection.ui b/krita/plugins/viewplugins/modify_selection/wdg_border_selection.ui new file mode 100644 index 00000000..621685da --- /dev/null +++ b/krita/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/krita/plugins/viewplugins/modify_selection/wdg_grow_selection.ui b/krita/plugins/viewplugins/modify_selection/wdg_grow_selection.ui new file mode 100644 index 00000000..d2eb12aa --- /dev/null +++ b/krita/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/krita/plugins/viewplugins/modify_selection/wdg_shrink_selection.ui b/krita/plugins/viewplugins/modify_selection/wdg_shrink_selection.ui new file mode 100644 index 00000000..2896325f --- /dev/null +++ b/krita/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/krita/plugins/viewplugins/performancetest/Makefile.am b/krita/plugins/viewplugins/performancetest/Makefile.am new file mode 100644 index 00000000..bcbd2d18 --- /dev/null +++ b/krita/plugins/viewplugins/performancetest/Makefile.am @@ -0,0 +1,24 @@ +kritarcdir = $(kde_datadir)/kritaplugins +kritarc_DATA = perftest.rc + +EXTRA_DIST = $(kritarc_DATA) + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = kritaperftest.la + +kritaperftest_la_SOURCES = wdg_perftest.ui perftest.cc dlg_perftest.cc +noinst_HEADERS = wdg_perftest.h dlg_perftest.h perftest.h + +kritaperftest_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritaperftest_la_LIBADD = ../../../libkritacommon.la + +kde_services_DATA = kritaperftest.desktop + +kritaperftest_la_METASOURCES = AUTO diff --git a/krita/plugins/viewplugins/performancetest/dlg_perftest.cc b/krita/plugins/viewplugins/performancetest/dlg_perftest.cc new file mode 100644 index 00000000..1d9a045e --- /dev/null +++ b/krita/plugins/viewplugins/performancetest/dlg_perftest.cc @@ -0,0 +1,110 @@ +/* + * dlg_perftest.cc - part of KimageShop^WKrayon^WKrita + * + * 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( QWidget * parent, + const char * name) + : super (parent, 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->sizeHint()); + + connect(this, SIGNAL(okClicked()), + this, SLOT(okClicked())); + + connect(m_page->btnSelectAll, SIGNAL(clicked()), this, SLOT(selectAllClicked())); + connect(m_page->btnDeselectAll, SIGNAL(clicked()), this, 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/krita/plugins/viewplugins/performancetest/dlg_perftest.h b/krita/plugins/viewplugins/performancetest/dlg_perftest.h new file mode 100644 index 00000000..7cb4f159 --- /dev/null +++ b/krita/plugins/viewplugins/performancetest/dlg_perftest.h @@ -0,0 +1,55 @@ +/* + * dlg_perftest.h -- part of KimageShop^WKrayon^WKrita + * + * 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 + +public: + + DlgPerfTest(QWidget * parent = 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/krita/plugins/viewplugins/performancetest/kritaperftest.desktop b/krita/plugins/viewplugins/performancetest/kritaperftest.desktop new file mode 100644 index 00000000..44af6558 --- /dev/null +++ b/krita/plugins/viewplugins/performancetest/kritaperftest.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=Krita/ViewPlugin +Type=Service +X-KDE-Library=kritaperftest +X-Krita-Version=2 diff --git a/krita/plugins/viewplugins/performancetest/perftest.cc b/krita/plugins/viewplugins/performancetest/perftest.cc new file mode 100644 index 00000000..1c5ede34 --- /dev/null +++ b/krita/plugins/viewplugins/performancetest/perftest.cc @@ -0,0 +1,1198 @@ +/* + * perftest.cc -- Part of Krita + * + * 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( kritaperftest, PerfTestFactory( "krita" ) ) + +PerfTest::PerfTest(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + if ( parent->inherits("KisView") ) + { + setInstance(PerfTestFactory::instance()); + setXMLFile(locate("data","kritaplugins/perftest.rc"), true); + + (void) new KAction(i18n("&Performance Test..."), 0, 0, this, SLOT(slotPerfTest()), actionCollection(), "perf_test"); + + m_view = (KisView*) parent; + } +} + +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")); + + QString report = QString(""); + + if (dlgPerfTest->exec() == QDialog::Accepted) { + + Q_INT32 testCount = (Q_INT32)qRound(dlgPerfTest->page()->intTestCount->value()); + + if (dlgPerfTest->page()->chkBitBlt->isChecked()) { + kdDebug() << "bltTest:\n"; + QString s = bltTest(testCount); + report = report.append(s); + kdDebug() << s << "\n"; + } + if (dlgPerfTest->page()->chkFill->isChecked()) { + kdDebug() << "Filltest\n"; + QString s= fillTest(testCount); + report = report.append(s); + kdDebug() << s << "\n"; + } + if (dlgPerfTest->page()->chkGradient->isChecked()) { + kdDebug() << "Gradienttest\n"; + QString s = gradientTest(testCount); + report = report.append(s); + kdDebug() << s << "\n"; + } + if (dlgPerfTest->page()->chkPixel->isChecked()) { + kdDebug() << "Pixeltest\n"; + QString s = pixelTest(testCount); + report = report.append(s); + kdDebug() << s << "\n"; + } + if (dlgPerfTest->page()->chkShape->isChecked()) { + kdDebug() << "Shapetest\n"; + QString s = shapeTest(testCount); + report = report.append(s); + kdDebug() << s << "\n"; + } + if (dlgPerfTest->page()->chkLayer->isChecked()) { + kdDebug() << "LayerTest\n"; + QString s = layerTest(testCount); + report = report.append(s); + kdDebug() << s << "\n"; + } + if (dlgPerfTest->page()->chkScale->isChecked()) { + kdDebug() << "Scaletest\n"; + QString s = scaleTest(testCount); + report = report.append(s); + kdDebug() << s << "\n"; + } + if (dlgPerfTest->page()->chkRotate->isChecked()) { + kdDebug() << "Rotatetest\n"; + QString s = rotateTest(testCount); + report = report.append(s); + kdDebug() << s << "\n"; + } + if (dlgPerfTest->page()->chkRender->isChecked()) { + kdDebug() << "Rendertest\n"; + QString s = renderTest(testCount); + report = report.append(s); + kdDebug() << s << "\n"; + } + if (dlgPerfTest->page()->chkSelection->isChecked()) { + kdDebug() << "Selectiontest\n"; + QString s = selectionTest(testCount); + report = report.append(s); + kdDebug() << s << "\n"; + } + if (dlgPerfTest->page()->chkColorConversion->isChecked()) { + kdDebug() << "Colorconversiontest\n"; + QString s = colorConversionTest(testCount); + report = report.append(s); + kdDebug() << s << "\n"; + } + if (dlgPerfTest->page()->chkFilter-> isChecked()) { + kdDebug() << "filtertest\n"; + QString s = filterTest(testCount); + report = report.append(s); + kdDebug() << s << "\n"; + } + if (dlgPerfTest->page()->chkReadBytes->isChecked()) { + kdDebug() << "Readbytes test\n"; + QString s = readBytesTest(testCount); + report = report.append(s); + kdDebug() << s << "\n"; + } + if (dlgPerfTest->page()->chkWriteBytes-> isChecked()) { + kdDebug() << "Writebytes test\n"; + QString s = writeBytesTest(testCount); + report = report.append(s); + kdDebug() << s << "\n"; + } + if (dlgPerfTest->page()->chkIterators->isChecked()) { + kdDebug() << "Iterators test\n"; + QString s = iteratorTest(testCount); + report = report.append(s); + kdDebug() << s << "\n"; + } + if (dlgPerfTest->page()->chkPaintView->isChecked()) { + kdDebug() << "paintview test\n"; + QString s = paintViewTest(testCount); + report = report.append(s); + kdDebug() << s << "\n"; + } + if (dlgPerfTest->page()->chkPaintViewFPS->isChecked()) { + kdDebug() << "paint current view (fps) test\n"; + QString 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"); + QTextEdit * e = new QTextEdit(d); + Q_CHECK_PTR(e); + d->setMainWidget(e); + e->setText(report); + e->setMinimumWidth(600); + e->setMinimumHeight(600); + d->exec(); + delete d; + + } + delete dlgPerfTest; +} + +QString PerfTest::bltTest(Q_UINT32 testCount) +{ + QString report = QString("* 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; + + +} + + +QString PerfTest::doBlit(const KisCompositeOp& op, + KisID cspace, + Q_UINT8 opacity, + Q_UINT32 testCount, + KisImageSP img) +{ + + QTime t; + QString 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(Qt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + pf.end(); + + t.restart(); + KisPainter p(img->activeDevice()); + for (Q_UINT32 i = 0; i < testCount; ++i) { + p.bitBlt(0, 0, op, small.data(),0,0,32, 32); + } + p.end(); + + report = report.append(QString(" %1 blits of rectangles < tilesize with opacity %2 and composite op %3: %4ms\n") + .arg(testCount) + .arg(opacity) + .arg(op.id().name()) + .arg(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(Qt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + pf.end(); + + t.restart(); + p.begin(img->activeDevice().data()); + for (Q_UINT32 i = 0; i < testCount; ++i) { + p.bitBlt(0, 0, op, medium.data(),0,0,96, 96); + } + p.end(); + + report = report.append(QString(" %1 blits of rectangles 3 * tilesize with opacity %2 and composite op %3: %4ms\n") + .arg(testCount) + .arg(opacity) + .arg(op.id().name()) + .arg(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(Qt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + pf.end(); + + t.restart(); + p.begin(img->activeDevice().data()); + for (Q_UINT32 i = 0; i < testCount; ++i) { + p.bitBlt(0, 0, op, big.data(),0,0,800,800); + + } + p.end(); + report = report.append(QString(" %1 blits of rectangles 800 x 800 with opacity %2 and composite op %3: %4ms\n") + .arg(testCount) + .arg(opacity) + .arg(op.id().name()) + .arg(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(Qt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + pf.end(); + + t.restart(); + p.begin(img->activeDevice().data()); + for (Q_UINT32 i = 0; i < testCount; ++i) { + p.bitBlt(600, 600, op, outside.data(),0,0,500,500); + + } + p.end(); + report = report.append(QString(" %1 blits of rectangles 500 x 500 at 600,600 with opacity %2 and composite op %3: %4ms\n") + .arg(testCount) + .arg(opacity) + .arg(op.id().name()) + .arg(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(Qt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8()), OPACITY_TRANSPARENT); + pf.fillRect(4, 4, 24, 24, KisColor(Qt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8()), OPACITY_OPAQUE / 2); + pf.fillRect(8, 8, 16, 16, KisColor(Qt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8()), OPACITY_OPAQUE); + pf.end(); + + t.restart(); + p.begin(img->activeDevice().data()); + for (Q_UINT32 i = 0; i < testCount; ++i) { + p.bitBlt(0, 0, op, small_with_alpha.data(), 0, 0, 32, 32); + } + p.end(); + + report = report.append(QString(" %1 blits of rectangles < tilesize with source alpha, with opacity %2 and composite op %3: %4ms\n") + .arg(testCount) + .arg(opacity) + .arg(op.id().name()) + .arg(t.elapsed())); + + return report; + +} + +QString PerfTest::fillTest(Q_UINT32 testCount) +{ + QString report = QString("* 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()); + QTime t; + t.restart(); + for (Q_UINT32 i = 0; i < testCount; ++i) { + p.eraseRect(0, 0, 1000, 1000); + } + report = report.append(QString(" Erased 1000 x 1000 layer %1 times: %2\n").arg(testCount).arg(t.elapsed())); + + + t.restart(); + for (Q_UINT32 i = 0; i < testCount; ++i) { + p.eraseRect(50, 50, 500, 500); + } + report = report.append(QString(" Erased 500 x 500 layer %1 times: %2\n").arg(testCount).arg(t.elapsed())); + + + t.restart(); + for (Q_UINT32 i = 0; i < testCount; ++i) { + p.eraseRect(-50, -50, 1100, 1100); + } + report = report.append(QString(" Erased rect bigger than layer %1 times: %2\n").arg(testCount).arg(t.elapsed())); + + + // Opaque Rect fill + t.restart(); + for (Q_UINT32 i = 0; i < testCount; ++i) { + p.fillRect(0, 0, 1000, 1000, KisColor(Qt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + } + report = report.append(QString(" Opaque fill 1000 x 1000 layer %1 times: %2\n").arg(testCount).arg(t.elapsed())); + + + t.restart(); + for (Q_UINT32 i = 0; i < testCount; ++i) { + p.fillRect(50, 50, 500, 500, KisColor(Qt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + } + report = report.append(QString(" Opaque fill 500 x 500 layer %1 times: %2\n").arg(testCount).arg(t.elapsed())); + + + t.restart(); + for (Q_UINT32 i = 0; i < testCount; ++i) { + p.fillRect(-50, -50, 1100, 1100, KisColor(Qt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + } + report = report.append(QString(" Opaque fill rect bigger than layer %1 times: %2\n").arg(testCount).arg(t.elapsed())); + + // Transparent rect fill + + t.restart(); + for (Q_UINT32 i = 0; i < testCount; ++i) { + p.fillRect(0, 0, 1000, 1000, KisColor(Qt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8()), OPACITY_OPAQUE / 2); + } + report = report.append(QString(" Opaque fill 1000 x 1000 layer %1 times: %2\n").arg(testCount).arg(t.elapsed())); + + + t.restart(); + for (Q_UINT32 i = 0; i < testCount; ++i) { + p.fillRect(50, 50, 500, 500, KisColor(Qt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8()), OPACITY_OPAQUE / 2); + } + report = report.append(QString(" Opaque fill 500 x 500 layer %1 times: %2\n").arg(testCount).arg(t.elapsed())); + + + t.restart(); + for (Q_UINT32 i = 0; i < testCount; ++i) { + p.fillRect(-50, -50, 1100, 1100, KisColor(Qt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8()), OPACITY_OPAQUE / 2); + } + report = report.append(QString(" Opaque fill rect bigger than layer %1 times: %2\n").arg(testCount).arg(t.elapsed())); + + // Colour fill + + t.restart(); + for (Q_UINT32 i = 0; i < testCount; ++i) { + p.eraseRect(0, 0, 1000, 1000); +// p.paintEllipse(500, 1000, 100, 0, 0); + p.setPaintColor(KisColor(Qt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + p.setFillThreshold(15); + p.setCompositeOp(COMPOSITE_OVER); + p.fillColor(0,0); + } + report = report.append(QString(" Opaque floodfill of whole circle (incl. erase and painting of circle) %1 times: %2\n").arg(testCount).arg(t.elapsed())); + + + // Pattern fill + t.restart(); + for (Q_UINT32 i = 0; i < testCount; ++i) { + p.eraseRect(0, 0, 1000, 1000); +// p.paintEllipse(500, 1000, 100, 0, 0); + p.setPaintColor(KisColor(Qt::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(QString(" Opaque patternfill of whole circle (incl. erase and painting of circle) %1 times: %2\n").arg(testCount).arg(t.elapsed())); + + + + } + + + + return report; + +} + +QString PerfTest::gradientTest(Q_UINT32 testCount) +{ + return QString("Gradient test\n"); +} + +QString PerfTest::pixelTest(Q_UINT32 testCount) +{ + QString report = QString("* 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(); + + QTime t; + t.restart(); + + QColor c = Qt::black; + Q_UINT8 opacity = OPACITY_OPAQUE; + for (Q_UINT32 i = 0; i < testCount; ++i) { + for (Q_UINT32 x = 0; x < 1000; ++x) { + for (Q_UINT32 y = 0; y < 1000; ++y) { + l->pixel(x, y, &c, &opacity); + } + } + } + report = report.append(QString(" read 1000 x 1000 pixels %1 times: %2\n").arg(testCount).arg(t.elapsed())); + + c= Qt::black; + t.restart(); + for (Q_UINT32 i = 0; i < testCount; ++i) { + for (Q_UINT32 x = 0; x < 1000; ++x) { + for (Q_UINT32 y = 0; y < 1000; ++y) { + l->setPixel(x, y, c, 128); + } + } + } + report = report.append(QString(" written 1000 x 1000 pixels %1 times: %2\n").arg(testCount).arg(t.elapsed())); + + } + + + + + return report; + +} + +QString PerfTest::shapeTest(Q_UINT32 testCount) +{ + return QString("Shape test\n"); +} + +QString PerfTest::layerTest(Q_UINT32 testCount) +{ + return QString("Layer test\n"); +} + +QString PerfTest::scaleTest(Q_UINT32 testCount) +{ + return QString("Scale test\n"); +} + +QString PerfTest::rotateTest(Q_UINT32 testCount) +{ + QString report = QString("* 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 ); + QTime 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(QString(" rotated 1000 x 1000 pixels over 360 degrees, degree by degree, %1 times: %2\n").arg(testCount).arg(t.elapsed())); + } + return report; +} + +QString PerfTest::renderTest(Q_UINT32 restCount) +{ + return QString("Render test\n"); +} + +QString PerfTest::selectionTest(Q_UINT32 testCount) +{ + return QString("Selection test\n"); +} + +QString PerfTest::colorConversionTest(Q_UINT32 testCount) +{ + QString report = QString("* 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,"")); + + QTime 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(QString(" converted from " + (*it).name() + " to " + (*it2).name() + " 1000 x 1000 pixels %1 times: %2\n").arg(testCount).arg(t.elapsed())); + + } + + delete img; + + } + return report; + +} + +QString PerfTest::filterTest(Q_UINT32 testCount) +{ + + QString report = QString("* 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(); + + QTime 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 (Q_UINT32 i = 0; i < testCount; ++i) { + f->enableProgress(); + f->process(l.data(), l.data(), f->configuration(f->createConfigurationWidget(m_view, l.data())), QRect(0, 0, 1000, 1000)); + f->disableProgress(); + } + report = report.append(QString(" filtered " + (*it).name() + "1000 x 1000 pixels %1 times: %2\n").arg(testCount).arg(t.elapsed())); + + } + + } + return report; + +} + +QString PerfTest::readBytesTest(Q_UINT32 testCount) +{ + QString report = QString("* 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(); + + QTime t; + t.restart(); + + for (Q_UINT32 i = 0; i < testCount; ++i) { + Q_UINT8 * newData = new Q_UINT8[1000 * 1000 * l->pixelSize()]; + Q_CHECK_PTR(newData); + l->readBytes(newData, 0, 0, 1000, 1000); + delete[] newData; + } + + report = report.append(QString(" read 1000 x 1000 pixels %1 times from empty image: %2\n").arg(testCount).arg(t.elapsed())); + + // On tiles with data + + KisFillPainter p(l.data()); + p.fillRect(0, 0, 1000, 1000, KisColor(Qt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + p.end(); + + t.restart(); + + for (Q_UINT32 i = 0; i < testCount; ++i) { + Q_UINT8 * newData = new Q_UINT8[1000 * 1000 * l->pixelSize()]; + Q_CHECK_PTR(newData); + l->readBytes(newData, 0, 0, 1000, 1000); + delete[] newData; + } + + report = report.append(QString(" read 1000 x 1000 pixels %1 times from filled image: %2\n").arg(testCount).arg(t.elapsed())); + + return report; +} + + +QString PerfTest::writeBytesTest(Q_UINT32 testCount) +{ + QString report = QString("* 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(Qt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + p.end(); + + + Q_UINT8 * data = new Q_UINT8[1000 * 1000 * l->pixelSize()]; + Q_CHECK_PTR(data); + l->readBytes(data, 0, 0, 1000, 1000); + + QTime t; + t.restart(); + for (Q_UINT32 i = 0; i < testCount; ++i) { + l->writeBytes(data, 0, 0, 1000, 1000); + } + delete[] data; + report = report.append(QString(" written 1000 x 1000 pixels %1 times: %2\n").arg(testCount).arg(t.elapsed())); + return report; + + +} + +/////// Iterator tests + + +QString hlineRODefault(KisDoc * doc, Q_UINT32 testCount) +{ + KisImageSP img = doc->newImage("", 1000, 1000, KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA", ""),"")); + KisPaintDeviceSP l = img->activeDevice(); + + QTime t; + t.restart(); + + + for (Q_UINT32 i = 0; i < testCount; ++i) { + int adv; + + for(Q_INT32 y2 = 0; y2 < 0 + 1000; y2++) + { + KisHLineIterator hiter = l->createHLineIterator(0, y2, 1000, false); + while(! hiter.isDone()) + { + adv = hiter.nConseqHPixels(); + hiter += adv; + } + } + + } + + return QString(" hline iterated read-only 1000 x 1000 pixels %1 times over default tile: %2\n").arg(testCount).arg(t.elapsed()); + + +} + +QString hlineRO(KisDoc * doc, Q_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(Qt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + p.end(); + + QTime t; + t.restart(); + + for (Q_UINT32 i = 0; i < testCount; ++i) { + int adv; + + for(Q_INT32 y2 = 0; y2 < 0 + 1000; y2++) + { + KisHLineIterator hiter = l->createHLineIterator(0, y2, 1000, false); + while(! hiter.isDone()) + { + adv = hiter.nConseqHPixels(); + hiter += adv; + } + } + + } + + return QString(" hline iterated read-only 1000 x 1000 pixels %1 times over existing tile: %2\n").arg(testCount).arg(t.elapsed()); + +} + +QString hlineWRDefault(KisDoc * doc, Q_UINT32 testCount) +{ + KisImageSP img = doc->newImage("", 1000, 1000, KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA", ""),"")); + KisPaintDeviceSP l = img->activeDevice(); + + QTime t; + t.restart(); + + for (Q_UINT32 i = 0; i < testCount; ++i) { + int adv; + + for(Q_INT32 y2 = 0; y2 < 0 + 1000; y2++) + { + KisHLineIterator hiter = l->createHLineIterator(0, y2, 1000, true); + while(! hiter.isDone()) + { + adv = hiter.nConseqHPixels(); + hiter += adv; + } + } + + } + + return QString(" hline iterated writable 1000 x 1000 pixels %1 times over default tile: %2\n").arg(testCount).arg(t.elapsed()); + +} + +QString hlineWR(KisDoc * doc, Q_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(Qt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + p.end(); + + + QTime t; + t.restart(); + + for (Q_UINT32 i = 0; i < testCount; ++i) { + int adv; + for(Q_INT32 y2 = 0; y2 < 0 + 1000; y2++) + { + KisHLineIterator hiter = l->createHLineIterator(0, y2, 1000, true); + while(! hiter.isDone()) + { + adv = hiter.nConseqHPixels(); + hiter += adv; + } + } + + } + + return QString(" hline iterated writable 1000 x 1000 pixels %1 times over existing tile: %2\n").arg(testCount).arg(t.elapsed()); + +} + + +QString vlineRODefault(KisDoc * doc, Q_UINT32 testCount) +{ + KisImageSP img = doc->newImage("", 1000, 1000, KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA", ""),"")); + KisPaintDeviceSP l = img->activeDevice(); + + QTime t; + t.restart(); + + for (Q_UINT32 i = 0; i < testCount; ++i) { + for(Q_INT32 y2 = 0; y2 < 0 + 1000; y2++) + { + KisVLineIterator hiter = l->createVLineIterator(y2, 0, 1000, true); + while(! hiter.isDone()) + { + ++hiter; + } + } + + } + + return QString(" vline iterated read-only 1000 x 1000 pixels %1 times over default tile: %2\n").arg(testCount).arg(t.elapsed()); + +} + +QString vlineRO(KisDoc * doc, Q_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(Qt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + p.end(); + + + QTime t; + t.restart(); + + for (Q_UINT32 i = 0; i < testCount; ++i) { + for(Q_INT32 y2 = 0; y2 < 0 + 1000; y2++) + { + KisVLineIterator hiter = l->createVLineIterator(y2, 0, 1000, true); + while(! hiter.isDone()) + { + ++hiter; + } + } + + } + + return QString(" vline iterated read-only 1000 x 1000 pixels %1 times over existing tile: %2\n").arg(testCount).arg(t.elapsed()); + +} + +QString vlineWRDefault(KisDoc * doc, Q_UINT32 testCount) +{ + KisImageSP img = doc->newImage("", 1000, 1000, KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA", ""),"")); + KisPaintDeviceSP l = img->activeDevice(); + + QTime t; + t.restart(); + + for (Q_UINT32 i = 0; i < testCount; ++i) { + + for(Q_INT32 y2 = 0; y2 < 0 + 1000; y2++) + { + KisVLineIterator hiter = l->createVLineIterator(y2, 0, 1000, true); + while(! hiter.isDone()) + { + ++hiter; + } + } + + } + + return QString(" vline iterated writable 1000 x 1000 pixels %1 times over default tile: %2\n").arg(testCount).arg(t.elapsed()); +} + +QString vlineWR(KisDoc * doc, Q_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(Qt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + p.end(); + + QTime t; + t.restart(); + + for (Q_UINT32 i = 0; i < testCount; ++i) { + for(Q_INT32 y2 = 0; y2 < 0 + 1000; y2++) + { + KisHLineIterator hiter = l->createHLineIterator(y2, 0, 1000, true); + while(! hiter.isDone()) + { + ++hiter; + } + } + + } + + return QString(" vline iterated writable 1000 x 1000 pixels %1 times over existing tile: %2\n").arg(testCount).arg(t.elapsed()); + +} + +QString rectRODefault(KisDoc * doc, Q_UINT32 testCount) +{ + KisImageSP img = doc->newImage("", 1000, 1000, KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA", ""),"")); + KisPaintDeviceSP l = img->activeDevice(); +; + QTime t; + t.restart(); + + for (Q_UINT32 i = 0; i < testCount; ++i) { + KisRectIterator r = l->createRectIterator(0, 0, 1000, 1000, false); + while(! r.isDone()) + { + ++r; + } + } + + return QString(" rect iterated read-only 1000 x 1000 pixels %1 times over default tile: %2\n").arg(testCount).arg(t.elapsed()); + + +} + +QString rectRO(KisDoc * doc, Q_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(Qt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + p.end(); + + QTime t; + t.restart(); + + for (Q_UINT32 i = 0; i < testCount; ++i) { + KisRectIterator r = l->createRectIterator(0, 0, 1000, 1000, false); + while(! r.isDone()) + { + ++r; + } + } + + return QString(" rect iterated read-only 1000 x 1000 pixels %1 times over existing tile: %2\n").arg(testCount).arg(t.elapsed()); + +} + +QString rectWRDefault(KisDoc * doc, Q_UINT32 testCount) +{ + + + KisImageSP img = doc->newImage("", 1000, 1000, KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA", ""),"")); + KisPaintDeviceSP l = img->activeDevice(); + + QTime t; + t.restart(); + + for (Q_UINT32 i = 0; i < testCount; ++i) { + KisRectIterator r = l->createRectIterator(0, 0, 1000, 1000, true); + while(! r.isDone()) + { + ++r; + } + } + + return QString(" rect iterated writable 1000 x 1000 pixels %1 times over default tile: %2\n").arg(testCount).arg(t.elapsed()); + +} + +QString rectWR(KisDoc * doc, Q_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(Qt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + p.end(); + + + QTime t; + t.restart(); + + + for (Q_UINT32 i = 0; i < testCount; ++i) { + KisRectIterator r = l->createRectIterator(0, 0, 1000, 1000, true); + while(! r.isDone()) + { + ++r; + } + } + + + return QString(" rect iterated writable 1000 x 1000 pixels %1 times over existing tile: %2\n").arg(testCount).arg(t.elapsed()); + + +} +QString PerfTest::iteratorTest(Q_UINT32 testCount) +{ + QString 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; + + +} + +QString PerfTest::paintViewTest(Q_UINT32 testCount) +{ + QString report = QString("* 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(Qt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + p.end(); + + QTime t; + t.restart(); + +#if USE_CALLGRIND + CALLGRIND_ZERO_STATS(); +#endif + + for (Q_UINT32 i = 0; i < testCount; ++i) { + m_view->getCanvasController()->updateCanvas(QRect(0, 0, 512, 512)); + } + +#if USE_CALLGRIND + CALLGRIND_DUMP_STATS(); +#endif + + report = report.append(QString(" painted a 512 x 512 image %1 times: %2 ms\n").arg(testCount).arg(t.elapsed())); + + img->newLayer("layer 2", OPACITY_OPAQUE); + l = img->activeDevice(); + + p.begin(l.data()); + p.fillRect(0, 0, 512, 512, KisColor(Qt::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(Qt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + p.end(); + + t.restart(); + + for (Q_UINT32 i = 0; i < testCount; ++i) { + m_view->getCanvasController()->updateCanvas(QRect(0, 0, 512, 512)); + } + + report = report.append(QString(" painted a 512 x 512 image with 3 layers %1 times: %2 ms\n").arg(testCount).arg(t.elapsed())); + + return report; +} + +QString PerfTest::paintViewFPSTest() +{ + QString report = QString("* paintView (fps) test\n\n"); + + QTime 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(QString(" painted current view at %1 frames per second\n").arg(numViewsPainted)); + + return report; +} + +#include "perftest.moc" diff --git a/krita/plugins/viewplugins/performancetest/perftest.h b/krita/plugins/viewplugins/performancetest/perftest.h new file mode 100644 index 00000000..6a3365c5 --- /dev/null +++ b/krita/plugins/viewplugins/performancetest/perftest.h @@ -0,0 +1,75 @@ +/* + * perftest.h -- Part of Krita + * + * 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 +public: + PerfTest(QObject *parent, const char *name, const QStringList &); + virtual ~PerfTest(); + +private slots: + + void slotPerfTest(); + +private: + + QString bltTest(Q_UINT32 testCount); + QString fillTest(Q_UINT32 testCount); + QString gradientTest(Q_UINT32 testCount); + QString pixelTest(Q_UINT32 testCount); + QString shapeTest(Q_UINT32 testCount); + QString layerTest(Q_UINT32 testCount); + QString scaleTest(Q_UINT32 testCount); + QString rotateTest(Q_UINT32 testCount); + QString renderTest(Q_UINT32 restCount); + QString selectionTest(Q_UINT32 testCount); + QString colorConversionTest(Q_UINT32 testCount); + QString filterTest(Q_UINT32 testCount); + QString readBytesTest(Q_UINT32 testCount); + QString writeBytesTest(Q_UINT32 testCount); + QString iteratorTest(Q_UINT32 testCount); + QString paintViewTest(Q_UINT32 testCount); + QString paintViewFPSTest(); + + QString doBlit(const KisCompositeOp& op, + KisID cspace, + Q_UINT8 opacity, + Q_UINT32 testCount, + KisImageSP img); + +private: + + KisView * m_view; + KisPainter * m_painter; + +}; + +#endif // PERFTEST_H_ diff --git a/krita/plugins/viewplugins/performancetest/perftest.rc b/krita/plugins/viewplugins/performancetest/perftest.rc new file mode 100644 index 00000000..6010e8f3 --- /dev/null +++ b/krita/plugins/viewplugins/performancetest/perftest.rc @@ -0,0 +1,9 @@ + + + + &Tools + + + + + \ No newline at end of file diff --git a/krita/plugins/viewplugins/performancetest/wdg_perftest.ui b/krita/plugins/viewplugins/performancetest/wdg_perftest.ui new file mode 100644 index 00000000..4f9ca4a0 --- /dev/null +++ b/krita/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 + + + + + layout5 + + + + unnamed + + + + btnSelectAll + + + &Select All + + + + + btnDeselectAll + + + &Deselect All + + + + + + + chkPaintViewFPS + + + PaintView (fps) + + + true + + + + + + + + intTestCount + + + + knuminput.h + knuminput.h + + diff --git a/krita/plugins/viewplugins/rotateimage/Makefile.am b/krita/plugins/viewplugins/rotateimage/Makefile.am new file mode 100644 index 00000000..55546f31 --- /dev/null +++ b/krita/plugins/viewplugins/rotateimage/Makefile.am @@ -0,0 +1,24 @@ +kritarcdir = $(kde_datadir)/kritaplugins +kritarc_DATA = rotateimage.rc + +EXTRA_DIST = $(kritarc_DATA) + + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = kritarotateimage.la + +kritarotateimage_la_SOURCES = wdg_rotateimage.ui rotateimage.cc dlg_rotateimage.cc +noinst_HEADERS = wdg_rotateimage.h dlg_rotateimage.h rotateimage.h + +kritarotateimage_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritarotateimage_la_LIBADD = ../../../libkritacommon.la + +kde_services_DATA = kritarotateimage.desktop + +kritarotateimage_la_METASOURCES = AUTO diff --git a/krita/plugins/viewplugins/rotateimage/dlg_rotateimage.cc b/krita/plugins/viewplugins/rotateimage/dlg_rotateimage.cc new file mode 100644 index 00000000..9bf20fec --- /dev/null +++ b/krita/plugins/viewplugins/rotateimage/dlg_rotateimage.cc @@ -0,0 +1,147 @@ +/* + * dlg_rotateimage.cc - part of KimageShop^WKrayon^WKrita + * + * 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( QWidget * parent, + const char * name) + : super (parent, 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->sizeHint()); + + connect(this, SIGNAL(okClicked()), + this, SLOT(okClicked())); + connect( m_page->doubleCustom, SIGNAL( valueChanged ( double ) ), + this, 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 = qRound(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/krita/plugins/viewplugins/rotateimage/dlg_rotateimage.h b/krita/plugins/viewplugins/rotateimage/dlg_rotateimage.h new file mode 100644 index 00000000..c6eef135 --- /dev/null +++ b/krita/plugins/viewplugins/rotateimage/dlg_rotateimage.h @@ -0,0 +1,65 @@ +/* + * dlg_rotateimage.h -- part of KimageShop^WKrayon^WKrita + * + * 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 + +public: + + DlgRotateImage(QWidget * parent = 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/krita/plugins/viewplugins/rotateimage/kritarotateimage.desktop b/krita/plugins/viewplugins/rotateimage/kritarotateimage.desktop new file mode 100644 index 00000000..6db00fc6 --- /dev/null +++ b/krita/plugins/viewplugins/rotateimage/kritarotateimage.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=Krita/ViewPlugin +Type=Service +X-KDE-Library=kritarotateimage +X-Krita-Version=2 diff --git a/krita/plugins/viewplugins/rotateimage/rotateimage.cc b/krita/plugins/viewplugins/rotateimage/rotateimage.cc new file mode 100644 index 00000000..8b85ef3a --- /dev/null +++ b/krita/plugins/viewplugins/rotateimage/rotateimage.cc @@ -0,0 +1,134 @@ +/* + * rotateimage.cc -- Part of Krita + * + * 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( kritarotateimage, RotateImageFactory( "krita" ) ) + +// XXX: this plugin could also provide layer scaling/resizing +RotateImage::RotateImage(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + + if ( parent->inherits("KisView") ) { + setInstance(RotateImageFactory::instance()); + setXMLFile(locate("data","kritaplugins/rotateimage.rc"), true); + m_view = (KisView*) parent; + (void) new KAction(i18n("&Rotate Image..."), 0, 0, this, SLOT(slotRotateImage()), actionCollection(), "rotateimage"); + (void) new KAction(i18n("Rotate Image CW"), "rotate_cw", 0, this, SLOT(slotRotateImage90()), actionCollection(), "rotateImageCW90"); + (void) new KAction(i18n("Rotate Image 1&80"), 0, 0, this, SLOT(slotRotateImage180()), actionCollection(), "rotateImage180"); + (void) new KAction(i18n("Rotate Image CCW"), "rotate_ccw", 0, this, SLOT(slotRotateImage270()), actionCollection(), "rotateImageCCW90"); + + (void) new KAction(i18n("&Rotate Layer..."), 0, 0, this, SLOT(slotRotateLayer()), actionCollection(), "rotatelayer"); + + (void)new KAction(i18n("Rotate 1&80"), 0, m_view, SLOT(rotateLayer180()), actionCollection(), "rotateLayer180"); + (void)new KAction(i18n("Rotate CCW"), "rotate_ccw", 0, m_view, SLOT(rotateLayerLeft90()), actionCollection(), "rotateLayerCCW90"); + (void)new KAction(i18n("Rotate CW"), "rotate_cw", 0, m_view, 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() == QDialog::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() == QDialog::Accepted) { + double angle = dlgRotateImage->angle(); + angle *= M_PI/180; + m_view->rotateLayer(angle); + } + delete dlgRotateImage; +} + +#include "rotateimage.moc" diff --git a/krita/plugins/viewplugins/rotateimage/rotateimage.h b/krita/plugins/viewplugins/rotateimage/rotateimage.h new file mode 100644 index 00000000..7c09179c --- /dev/null +++ b/krita/plugins/viewplugins/rotateimage/rotateimage.h @@ -0,0 +1,49 @@ +/* + * rotateimage.h -- Part of Krita + * + * 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 +public: + RotateImage(QObject *parent, const char *name, const QStringList &); + 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/krita/plugins/viewplugins/rotateimage/rotateimage.rc b/krita/plugins/viewplugins/rotateimage/rotateimage.rc new file mode 100644 index 00000000..b5f19e6a --- /dev/null +++ b/krita/plugins/viewplugins/rotateimage/rotateimage.rc @@ -0,0 +1,25 @@ + + + + &Image + &Rotate + + + + + + + + + La&yer + &Rotate + + + + + + + + + + diff --git a/krita/plugins/viewplugins/rotateimage/wdg_rotateimage.ui b/krita/plugins/viewplugins/rotateimage/wdg_rotateimage.ui new file mode 100644 index 00000000..f672db7f --- /dev/null +++ b/krita/plugins/viewplugins/rotateimage/wdg_rotateimage.ui @@ -0,0 +1,245 @@ + +WdgRotateImage + + + WdgRotateImage + + + + 0 + 0 + 489 + 447 + + + + Rotate Image + + + + unnamed + + + + grpDirection + + + Direction + + + + unnamed + + + + layout6 + + + + 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 + + + + + layout1 + + + + unnamed + + + + radioCustom + + + &Custom: + + + true + + + + + doubleCustom + + + 360 + + + 1 + + + + + + + + + spacer4 + + + Vertical + + + Expanding + + + + 20 + 91 + + + + + + + + + + 89504e470d0a1a0a0000000d494844520000002c0000002e0806000000534cfb0a0000013a494441545885ed994b0ec330084487aaf7bf32dd5689297f9b489d6d24fc3c02db106266a445c460a67c205daf7404a2821ddb9503de0c0b64800fc00251e043b00040eea28bc21615a50fb8cad904bc1db8230d02e0671cbeca01ee2bbaaecbc16184bfe8a405b4cd58a00c86c48eb588d3cc54b1a9f8c5114d0f0d5c81ce5dcd999c0e42e71f3f5dd0826245572dc9d1c586f20e57a8ed1cdead85f373808d2ecf01366a16f0cae54b5acc0236e80fdcadc701bfc52f99c77ae35065edf0c1ae58d31d78302c302d870d9dcc2c6083e4a2bbaa7b3a694cc5bbc39bc6a626a5dec39dc5e888bd06965cee8076741b40a4e82aa103b164e0442b6ed2af183fd6d69b500dce5ba4c978b6aeb962cc5434aa3a3b6efd56794fd7793e3b62d74d2f23da3ef939f0bfa36e54557d9a48cb8c98ad39f4b8e7e5e3803f91a1a32701eeec170000000049454e44ae426082 + + + 89504e470d0a1a0a0000000d494844520000002c0000002e0806000000534cfb0a00000132494441545885ed994b12032108449b54ee7f65b3cd5440f92a56a5f7326f5a11451a63608b8806c6a0689857068b5a446177f6020361e8fdc04008fa0c30e086a6b4a4f3ba664cc418704212013041fb80b340bfa5847e9b825680022687f549d70016d03aac815d7d988be1a87c6be015acb7dc3ac7cd8167b091734160acbc861bc2029e4a77101690f661c9dd840f46a577b8012cc00157edb749d239dcc45de0e4f1d2a927705235aad4e50e5fa03f70b56c0778ab227bba90ec7d1d167eb62f30c0423f81b9696856aa7b3bcc487fa7f3543ccb18e54cfe3adca914332ce7aff9c6d83cb0e47205b4f176634fba4c68472c1978b69633a09db7f2753330bb91128ca7eb5e56b5aaac316069b756573ce54cf5b8e65fd3d0769870e6c920305bfb1e659296541ef0265d77bcbc0ef803779f9c39421cd9b50000000049454e44ae426082 + + + + + knuminput.h + + diff --git a/krita/plugins/viewplugins/screenshot/Makefile.am b/krita/plugins/viewplugins/screenshot/Makefile.am new file mode 100644 index 00000000..616ebdcd --- /dev/null +++ b/krita/plugins/viewplugins/screenshot/Makefile.am @@ -0,0 +1,26 @@ +kritarcdir = $(kde_datadir)/kritaplugins +kritarc_DATA = screenshot-krita.rc + +EXTRA_DIST = $(kritarc_DATA) + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = kritascreenshot.la + +kritascreenshot_la_SOURCES = screenshot.cpp ksnapshot.cpp regiongrabber.cpp ksnapshotwidget.ui +noinst_HEADERS = screenshot.h ksnapshot.h regiongrabber.h ksnapshotwidget.h ksnapshotwidget.ui.h + +kritascreenshot_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritascreenshot_la_LIBADD = ../../../libkritacommon.la + +kde_services_DATA = kritascreenshot.desktop + +kritascreenshot_la_METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) *.cpp -o $(podir)/kscreenshot_plugin.pot diff --git a/krita/plugins/viewplugins/screenshot/kritascreenshot.desktop b/krita/plugins/viewplugins/screenshot/kritascreenshot.desktop new file mode 100644 index 00000000..2420e527 --- /dev/null +++ b/krita/plugins/viewplugins/screenshot/kritascreenshot.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=Krita/ViewPlugin +Type=Service +X-KDE-Library=kritascreenshot +X-Krita-Version=2 diff --git a/krita/plugins/viewplugins/screenshot/ksnapshot.cpp b/krita/plugins/viewplugins/screenshot/ksnapshot.cpp new file mode 100644 index 00000000..77b4da4b --- /dev/null +++ b/krita/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(QWidget *parent, const char *name) + : super(parent, name, false, QString::null, Ok|Cancel) +{ + grabber = new QWidget( 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 + + QVBox *vbox = makeVBoxMainWidget(); + mainWidget = new KSnapshotWidget( vbox, "mainWidget" ); + Q_CHECK_PTR(mainWidget); + + mainWidget->btnSave->hide(); + mainWidget->btnPrint->hide(); + connect(mainWidget, SIGNAL(startImageDrag()), SLOT(slotDragSnapshot())); + + connect( mainWidget, SIGNAL( newClicked() ), SLOT( slotGrab() ) ); + connect( mainWidget, SIGNAL( printClicked() ), SLOT( slotPrint() ) ); + + grabber->show(); + grabber->grabMouse( waitCursor ); + + snapshot = QPixmap::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, SIGNAL( timeout() ), this, SLOT( grabTimerDone() ) ); + + KAccel* accel = new KAccel(this); + Q_CHECK_PTR(accel); + accel->insert(KStdAccel::Print, this, SLOT(slotPrint())); + accel->insert(KStdAccel::New, this, SLOT(slotGrab())); + + accel->insert( "Print2", Qt::Key_P, this, SLOT(slotPrint())); + accel->insert( "New2", Qt::Key_N, this, SLOT(slotGrab())); + accel->insert( "New3", Qt::Key_Space, this, SLOT(slotGrab())); + + mainWidget->btnNew->setFocus(); + +} + +KSnapshot::~KSnapshot() +{ +} + +bool KSnapshot::save( const QString &filename ) +{ + return save( KURL::fromPathOrURL( filename )); +} + +bool KSnapshot::save( const KURL& url ) +{ + QString 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 ); + } + } + } + + QApplication::restoreOverrideCursor(); + if ( !ok ) { + kdWarning() << "KSnapshot was unable to save the snapshot" << endl; + + QString caption = i18n("Unable to Save Image"); + QString text = i18n("KSnapshot was unable to save the image to\n%1.") + .arg(url.prettyURL()); + KMessageBox::error(this, text, caption); + } + + return ok; +} + +void KSnapshot::slotCopy() +{ + QClipboard *cb = QApplication::clipboard(); + cb->setPixmap( snapshot ); +} + +void KSnapshot::slotDragSnapshot() +{ + QDragObject *drobj = new QImageDrag(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, SIGNAL( regionGrabbed( const QPixmap & ) ), + SLOT( slotRegionGrabbed( const QPixmap & ) ) ); + } + 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); + + qApp->processEvents(); + + if (printer.setup(this, i18n("Print Screenshot"))) + { + qApp->processEvents(); + + QPainter painter(&printer); + QPaintDeviceMetrics 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 ) { + + QImage img = snapshot.convertToImage(); + qApp->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), QImage::ScaleMin ); + qApp->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 ); + } + } + + qApp->processEvents(); +} + +void KSnapshot::slotRegionGrabbed( const QPixmap &pix ) +{ + if ( !pix.isNull() ) + { + snapshot = pix; + updatePreview(); + modified = true; + } + + delete rgnGrab; + QApplication::restoreOverrideCursor(); + show(); +} + +bool KSnapshot::eventFilter( QObject* o, QEvent* e) +{ + if ( o == grabber && e->type() == QEvent::MouseButtonPress ) { + QMouseEvent* me = (QMouseEvent*) e; + if ( QWidget::mouseGrabber() != grabber ) + return false; + if ( me->button() == LeftButton ) + performGrab(); + } + return false; +} + +void KSnapshot::updatePreview() +{ + QImage 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() ) ); + + QPixmap 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, parent; + Window* children; + unsigned int nchildren; + Window ret = None; + if( XQueryTree( qt_xdisplay(), w, &root, &parent, &children, &nchildren ) != 0 ) { + for( unsigned int i = 0; + i < nchildren && ret == None; + ++i ) + ret = findRealWindow( children[ i ], depth + 1 ); + if( children != NULL ) + XFree( children ); + } + return ret; +} + +void KSnapshot::performGrab() +{ + grabber->releaseMouse(); + grabber->hide(); + grabTimer.stop(); + XGrabServer( qt_xdisplay()); + if ( mainWidget->mode() == WindowUnderCursor ) { + Window root; + Window child; + uint mask; + int rootX, rootY, winX, winY; + XQueryPointer( qt_xdisplay(), qt_xrootwin(), &root, &child, + &rootX, &rootY, &winX, &winY, + &mask); + 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 parent; + Window* children; + unsigned int nchildren; + if( XQueryTree( qt_xdisplay(), child, &root, &parent, + &children, &nchildren ) != 0 ) { + if( children != NULL ) + XFree( children ); + int newx, newy; + Window dummy; + if( XTranslateCoordinates( qt_xdisplay(), parent, qt_xrootwin(), + x, y, &newx, &newy, &dummy )) { + x = newx; + y = newy; + } + } + + snapshot = QPixmap::grabWindow( qt_xrootwin(), x, y, w, h ); + +#ifdef HAVE_X11_EXTENSIONS_SHAPE_H + //No XShape - no work. + if (haveXShape) { + QBitmap mask(w, h); + //As the first step, get the mask from XShape. + int count, order; + XRectangle* rects = XShapeGetRectangles( qt_xdisplay(), child, + ShapeBounding, &count, &order); + //The ShapeBounding region is the outermost shape 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 QRegion from the rectangles describing the bounding mask. + QRegion contents; + for (int pos = 0; pos < count; pos++) + contents += QRegion(rects[pos].x, rects[pos].y, + rects[pos].width, rects[pos].height); + XFree(rects); + + //Create the bounding box. + QRegion bbox(0, 0, snapshot.width(), snapshot.height()); + + if( border > 0 ) { + contents.translate( border, border ); + contents += QRegion( 0, 0, border, h ); + contents += QRegion( 0, 0, w, border ); + contents += QRegion( 0, h - border, w, border ); + contents += QRegion( w - border, 0, border, h ); + } + + //Get the masked away area. + QRegion maskedAway = bbox - contents; + QMemArray maskedAwayRects = maskedAway.rects(); + + //Construct a bitmap mask from the rectangles + QPainter p(&mask); + p.fillRect(0, 0, w, h, Qt::color1); + for (uint pos = 0; pos < maskedAwayRects.count(); pos++) + p.fillRect(maskedAwayRects[pos], Qt::color0); + p.end(); + + snapshot.setMask(mask); + } + } +#endif + } + else { + snapshot = QPixmap::grabWindow( qt_xrootwin() ); + } + XUngrabServer( qt_xdisplay()); + updatePreview(); + QApplication::restoreOverrideCursor(); + modified = true; +// show(); + slotOk(); +} + +void KSnapshot::setTime(int newTime) +{ + mainWidget->setDelay(newTime); +} + +void KSnapshot::setURL( const QString &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) +{ + QCursor::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( QString::null ); + 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( QString::null ); + conf->writePathEntry("filename",url.url()); + + emit screenGrabbed(); + + accept(); +} + +#include "ksnapshot.moc" diff --git a/krita/plugins/viewplugins/screenshot/ksnapshot.h b/krita/plugins/viewplugins/screenshot/ksnapshot.h new file mode 100644 index 00000000..7eeccb62 --- /dev/null +++ b/krita/plugins/viewplugins/screenshot/ksnapshot.h @@ -0,0 +1,135 @@ +// -*- 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 QLabel +{ + Q_OBJECT + +public: + KSnapshotThumb(QWidget *parent, const char *name = 0) + : QLabel(parent, name) + { + setAlignment(AlignHCenter | AlignVCenter); + } + virtual ~KSnapshotThumb() {} + +signals: + void startDrag(); + +protected: + void mousePressEvent(QMouseEvent * e) + { + mClickPt = e->pos(); + } + + void mouseMoveEvent(QMouseEvent * e) + { + if (mClickPt != QPoint(0, 0) && + (e->pos() - mClickPt).manhattanLength() > KGlobalSettings::dndEventDelay()) + { + mClickPt = QPoint(0, 0); + emit startDrag(); + } + } + + void mouseReleaseEvent(QMouseEvent * /*e*/) + { + mClickPt = QPoint(0, 0); + } + + QPoint mClickPt; +}; + +class KSnapshot : public KDialogBase +{ + typedef KDialogBase super; + Q_OBJECT + +public: + KSnapshot(QWidget *parent= 0, const char *name= 0); + ~KSnapshot(); + + enum CaptureMode { FullScreen=0, WindowUnderCursor=1, Region=2 }; + + bool save( const QString &filename ); + bool save( const KURL& url ); + + QString 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 QString &newURL); + void setGrabMode( int m ); + void exit(); + + void slotOk(); + + +protected: + void reject() { close(); } + bool eventFilter( QObject*, QEvent* ); + +private slots: + void grabTimerDone(); + void slotDragSnapshot(); + void slotRegionGrabbed( const QPixmap & ); + +private: + void updatePreview(); + void performGrab(); + void autoincFilename(); + + QPixmap snapshot; + QTimer grabTimer; + QWidget* grabber; + KURL filename; + KSnapshotWidget *mainWidget; + RegionGrabber *rgnGrab; + bool modified; + bool haveXShape; +}; + +#endif // KSNAPSHOT_H + diff --git a/krita/plugins/viewplugins/screenshot/ksnapshotwidget.ui b/krita/plugins/viewplugins/screenshot/ksnapshotwidget.ui new file mode 100644 index 00000000..bd24e6ef --- /dev/null +++ b/krita/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 QPixmap & pm ) + setDelay( int i ) + setIncludeDecorations( bool b ) + setMode( int mode ) + delay() + includeDecorations() + mode() + preview() + +SmallIconSet + + +
diff --git a/krita/plugins/viewplugins/screenshot/ksnapshotwidget.ui.h b/krita/plugins/viewplugins/screenshot/ksnapshotwidget.ui.h new file mode 100644 index 00000000..e61b0c6e --- /dev/null +++ b/krita/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 +** Qt 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 QPixmap &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(); +} + + +QPixmap KSnapshotWidget::preview() +{ + return *lblImage->pixmap(); +} + + +int KSnapshotWidget::previewWidth() +{ + return lblImage->width(); +} + + +int KSnapshotWidget::previewHeight() +{ + return lblImage->height(); +} + diff --git a/krita/plugins/viewplugins/screenshot/main.cpp b/krita/plugins/viewplugins/screenshot/main.cpp new file mode 100644 index 00000000..70f61349 --- /dev/null +++ b/krita/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/krita/plugins/viewplugins/screenshot/regiongrabber.cpp b/krita/plugins/viewplugins/screenshot/regiongrabber.cpp new file mode 100644 index 00000000..f42f6b94 --- /dev/null +++ b/krita/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( QWidget *parent, const char *name ) + : QLabel( parent, name, WStyle_Customize | WX11BypassWM | + WStyle_StaysOnTop | WStyle_NoBorder | WStyle_Tool ) +{ + setMargin( 2 ); + setIndent( 0 ); + setFrameStyle( QFrame::Plain | QFrame::Box ); + + setPalette( QToolTip::palette() ); +} + +void SizeTip::setTip( const QRect &rect ) +{ + QString tip = QString( "%1x%2" ).arg( rect.width() ) + .arg( rect.height() ); + + setText( tip ); + adjustSize(); + + positionTip( rect ); +} + +void SizeTip::positionTip( const QRect &rect ) +{ + QRect tipRect = geometry(); + tipRect.moveTopLeft( QPoint( 0, 0 ) ); + + if ( rect.intersects( tipRect ) ) + { + QRect deskR = KGlobalSettings::desktopGeometry( QPoint( 0, 0 ) ); + + tipRect.moveCenter( QPoint( deskR.width()/2, deskR.height()/2 ) ); + if ( !rect.contains( tipRect, true ) && rect.intersects( tipRect ) ) + tipRect.moveBottomRight( geometry().bottomRight() ); + } + + move( tipRect.topLeft() ); +} + +RegionGrabber::RegionGrabber() + : QWidget( 0, 0 ), + mouseDown( false ), sizeTip( 0L ) +{ + sizeTip = new SizeTip( ( QWidget * )0L ); + + tipTimer = new QTimer( this ); + Q_CHECK_PTR(tipTimer); + connect( tipTimer, SIGNAL( timeout() ), SLOT( updateSizeTip() ) ); + + QTimer::singleShot( 200, this, SLOT( initGrabber() ) ); +} + +RegionGrabber::~RegionGrabber() +{ + delete sizeTip; +} + +void RegionGrabber::initGrabber() +{ + pixmap = QPixmap::grabWindow( qt_xrootwin() ); + setPaletteBackgroundPixmap( pixmap ); + + showFullScreen(); + + grabMouse( crossCursor ); +} + +void RegionGrabber::mousePressEvent( QMouseEvent *e ) +{ + if ( e->button() == LeftButton ) + { + mouseDown = true; + grabRect = QRect( e->pos(), e->pos() ); + } +} + +void RegionGrabber::mouseMoveEvent( QMouseEvent *e ) +{ + if ( mouseDown ) + { + sizeTip->hide(); + tipTimer->start( 250, true ); + + drawRubber(); + grabRect.setBottomRight( e->pos() ); + drawRubber(); + } +} + +void RegionGrabber::mouseReleaseEvent( QMouseEvent *e ) +{ + mouseDown = false; + drawRubber(); + sizeTip->hide(); + + grabRect.setBottomRight( e->pos() ); + grabRect = grabRect.normalize(); + + QPixmap region = QPixmap::grabWindow( winId(), grabRect.x(), grabRect.y(), + grabRect.width(), grabRect.height() ); + + releaseMouse(); + + emit regionGrabbed( region ); +} + +void RegionGrabber::keyPressEvent( QKeyEvent *e ) +{ + if ( e->key() == Qt::Key_Escape ) + { + releaseMouse(); + emit regionGrabbed( QPixmap() ); + } + else + e->ignore(); +} + +void RegionGrabber::updateSizeTip() +{ + QRect rect = grabRect.normalize(); + + sizeTip->setTip( rect ); + sizeTip->show(); +} + +void RegionGrabber::drawRubber() +{ + QPainter p; + p.begin( this ); + p.setRasterOp( NotROP ); + p.setPen( QPen( color0, 1 ) ); + p.setBrush( NoBrush ); + + style().drawPrimitive( QStyle::PE_FocusRect, &p, grabRect, colorGroup(), + QStyle::Style_Default, QStyleOption( colorGroup().base() ) ); + + p.end(); +} + +#include "regiongrabber.moc" diff --git a/krita/plugins/viewplugins/screenshot/regiongrabber.h b/krita/plugins/viewplugins/screenshot/regiongrabber.h new file mode 100644 index 00000000..74bf78c9 --- /dev/null +++ b/krita/plugins/viewplugins/screenshot/regiongrabber.h @@ -0,0 +1,71 @@ +/* + * 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 QTimer; + +class SizeTip : public QLabel +{ +public: + SizeTip( QWidget *parent, const char *name=0 ); + ~SizeTip() {} + + void setTip( const QRect &rect ); + void positionTip( const QRect &rect ); +}; + +class RegionGrabber : public QWidget +{ + Q_OBJECT + +public: + RegionGrabber(); + ~RegionGrabber(); + +protected slots: + void initGrabber(); + void updateSizeTip(); + + signals: + void regionGrabbed( const QPixmap & ); + +protected: + void mousePressEvent( QMouseEvent *e ); + void mouseReleaseEvent( QMouseEvent *e ); + void mouseMoveEvent( QMouseEvent *e ); + void keyPressEvent( QKeyEvent *e ); + + void drawRubber(); + + bool mouseDown; + QRect grabRect; + QPixmap pixmap; + + SizeTip *sizeTip; + QTimer *tipTimer; +}; + +#endif // REGIONGRABBER_H + diff --git a/krita/plugins/viewplugins/screenshot/screenshot-kpresenter.rc b/krita/plugins/viewplugins/screenshot/screenshot-kpresenter.rc new file mode 100644 index 00000000..14cd9d2e --- /dev/null +++ b/krita/plugins/viewplugins/screenshot/screenshot-kpresenter.rc @@ -0,0 +1,9 @@ + + + + &Insert + + + + + diff --git a/krita/plugins/viewplugins/screenshot/screenshot-krita.rc b/krita/plugins/viewplugins/screenshot/screenshot-krita.rc new file mode 100644 index 00000000..07f14197 --- /dev/null +++ b/krita/plugins/viewplugins/screenshot/screenshot-krita.rc @@ -0,0 +1,9 @@ + + + + &Tools + + + + + diff --git a/krita/plugins/viewplugins/screenshot/screenshot-kword.rc b/krita/plugins/viewplugins/screenshot/screenshot-kword.rc new file mode 100644 index 00000000..f1f3fce1 --- /dev/null +++ b/krita/plugins/viewplugins/screenshot/screenshot-kword.rc @@ -0,0 +1,9 @@ + + + + &Insert + + + + + diff --git a/krita/plugins/viewplugins/screenshot/screenshot.cpp b/krita/plugins/viewplugins/screenshot/screenshot.cpp new file mode 100644 index 00000000..c7508ae9 --- /dev/null +++ b/krita/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( kritascreenshot, KGenericFactory( "krita" ) ) + +Screenshot::Screenshot(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + KGlobal::locale()->insertCatalogue("kscreenshot_plugin"); + setInstance(KGenericFactory::instance()); + setXMLFile(locate("data","kritaplugins/screenshot-krita.rc"), true); + KImageIO::registerFormats(); + + snapshot = new KSnapshot(); + Q_CHECK_PTR(snapshot); + connect( snapshot, SIGNAL( screenGrabbed() ), SLOT( slotScreenGrabbed() ) ); + + (void) new KAction(i18n("&Screenshot..."), SmallIcon("tool_screenshot"), 0, this, 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(parent()); + if(view) + view->importImage(temp.name()); +} diff --git a/krita/plugins/viewplugins/screenshot/screenshot.h b/krita/plugins/viewplugins/screenshot/screenshot.h new file mode 100644 index 00000000..5e4c7c5d --- /dev/null +++ b/krita/plugins/viewplugins/screenshot/screenshot.h @@ -0,0 +1,42 @@ +/* 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 +public: + Screenshot(QObject *parent, const char *name, const QStringList &); + virtual ~Screenshot(); + +private slots: + void slotScreenshot(); + void slotScreenGrabbed(); + +private: + KSnapshot * snapshot; +}; + +#endif diff --git a/krita/plugins/viewplugins/scripting/Makefile.am b/krita/plugins/viewplugins/scripting/Makefile.am new file mode 100644 index 00000000..f361a6ce --- /dev/null +++ b/krita/plugins/viewplugins/scripting/Makefile.am @@ -0,0 +1,28 @@ +SUBDIRS = kritascripting kritacore samples + +kritarcdir = $(kde_datadir)/kritaplugins +kritarc_DATA = scripting.rc + +kde_services_DATA = kritascripting.desktop + + +INCLUDES = -I$(top_srcdir)/krita/sdk \ + -I$(top_srcdir)/krita/core \ + -I$(top_srcdir)/krita/kritacolor/ \ + -I$(top_srcdir)/krita/ui \ + -I$(top_builddir)/lib/kross/main \ + $(KROSS_INCLUDES) \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kritascripting_la_SOURCES = scripting.cc + +kde_module_LTLIBRARIES = kritascripting.la +noinst_HEADERS = scripting.h + +kritascripting_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritascripting_la_LIBADD = $(top_builddir)/krita/libkritacommon.la $(top_builddir)/lib/kross/main/libkrossmain.la ./kritascripting/libkritascripting.la + +KDE_CXXFLAGS = $(USE_EXCEPTIONS) + +kritascripting_la_METASOURCES = AUTO diff --git a/krita/plugins/viewplugins/scripting/kritacore/Makefile.am b/krita/plugins/viewplugins/scripting/kritacore/Makefile.am new file mode 100644 index 00000000..e948f647 --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritacore/Makefile.am @@ -0,0 +1,29 @@ + +INCLUDES = -I$(top_srcdir)/core -I$(top_srcdir)/krita/plugins/viewplugins/scripting/kritascripting \ + -I$(top_srcdir)/krita $(KOFFICECORE_INCLUDES) $(KROSS_INCLUDES) \ + -I$(top_srcdir)/krita/ui -I$(top_srcdir)/krita/core -I$(top_srcdir)/krita/sdk \ + -I$(top_srcdir)/krita/kritacolor $(all_includes) + +kde_module_LTLIBRARIES = krosskritacore.la + +krosskritacore_la_SOURCES = kritacoremodule.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 + +krosskritacore_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module +krosskritacore_la_LIBADD = \ + $(LIB_QT) \ + $(LIB_KDECORE) \ + $(top_builddir)/lib/kross/api/libkrossapi.la \ + $(top_builddir)/lib/kross/main/libkrossmain.la \ + $(top_builddir)/krita/libkritacommon.la \ + $(top_builddir)/krita/plugins/viewplugins/scripting/kritascripting/libkritascripting.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/krita/plugins/viewplugins/scripting/kritacore/kritacoremodule.cpp b/krita/plugins/viewplugins/scripting/kritacore/kritacoremodule.cpp new file mode 100644 index 00000000..899291ce --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritacore/kritacoremodule.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 "kritacoremodule.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::KritaCore::KritaCoreModule(manager); + } +} + + +using namespace Kross::KritaCore; + +KritaCoreFactory::KritaCoreFactory(QString packagePath) : Kross::Api::Event("KritaCoreFactory"), m_packagePath(packagePath) +{ + addFunction("newRGBColor", &KritaCoreFactory::newRGBColor); + addFunction("newHSVColor", &KritaCoreFactory::newHSVColor); + addFunction("getPattern", &KritaCoreFactory::getPattern); + addFunction("loadPattern", &KritaCoreFactory::loadPattern); + addFunction("getBrush", &KritaCoreFactory::getBrush); + addFunction("loadBrush", &KritaCoreFactory::loadBrush); + addFunction("getFilter", &KritaCoreFactory::getFilter); + addFunction("newCircleBrush", &KritaCoreFactory::newCircleBrush); + addFunction("newRectBrush", &KritaCoreFactory::newRectBrush); + addFunction("newImage", &KritaCoreFactory::newImage); + addFunction("getPackagePath", &KritaCoreFactory::getPackagePath); +} + +Kross::Api::Object::Ptr KritaCoreFactory::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)), QColor::Rgb); + return c; +} +Kross::Api::Object::Ptr KritaCoreFactory::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)), QColor::Hsv); +} + +Kross::Api::Object::Ptr KritaCoreFactory::getPattern(Kross::Api::List::Ptr args) +{ + KisResourceServerBase* rServer = KisResourceServerRegistry::instance()->get("PatternServer"); + QValueList resources = rServer->resources(); + + QString name = Kross::Api::Variant::toString(args->item(0)); + + for (QValueList::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 KritaCoreFactory::loadPattern(Kross::Api::List::Ptr args) +{ + QString 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 KritaCoreFactory::getBrush(Kross::Api::List::Ptr args) +{ + KisResourceServerBase* rServer = KisResourceServerRegistry::instance()->get("BrushServer"); + QValueList resources = rServer->resources(); + + QString name = Kross::Api::Variant::toString(args->item(0)); + + for (QValueList::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 KritaCoreFactory::loadBrush(Kross::Api::List::Ptr args) +{ + QString 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 KritaCoreFactory::getFilter(Kross::Api::List::Ptr args) +{ + QString 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 KritaCoreFactory::newCircleBrush(Kross::Api::List::Ptr args) +{ + uint w = QMAX(1, Kross::Api::Variant::toUInt(args->item(0))); + uint h = QMAX(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); + QImage* brsh = new QImage(); + kas->createBrush(brsh); + return new Brush(new KisAutobrushResource(*brsh), false); +} +Kross::Api::Object::Ptr KritaCoreFactory::newRectBrush(Kross::Api::List::Ptr args) +{ + uint w = QMAX(1, Kross::Api::Variant::toUInt(args->item(0))); + uint h = QMAX(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); + QImage* brsh = new QImage(); + kas->createBrush(brsh); + return new Brush(new KisAutobrushResource(*brsh), false);; +} + +Kross::Api::Object::Ptr KritaCoreFactory::newImage(Kross::Api::List::Ptr args) +{ + int w = Kross::Api::Variant::toInt(args->item(0)); + int h = Kross::Api::Variant::toInt(args->item(1)); + QString csname = Kross::Api::Variant::toString(args->item(2)); + QString 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.").arg(csname ) ) ); + return 0; + } + + return new Image(new KisImage(0,w,h, cs, name)); +} + +Kross::Api::Object::Ptr KritaCoreFactory::getPackagePath(Kross::Api::List::Ptr) +{ + return new Kross::Api::Variant(m_packagePath); +} + +KritaCoreModule::KritaCoreModule(Kross::Api::Manager* manager) + : Kross::Api::Module("kritacore") , m_manager(manager), m_factory(0) +{ + + QMap children = manager->getChildren(); + kdDebug(41011) << " there are " << children.size() << endl; + for(QMap::const_iterator it = children.begin(); it != children.end(); it++) + { + kdDebug(41011) << it.key() << " " << it.data() << endl; + } + + // Wrap doc + Kross::Api::Object::Ptr kritadocument = manager->getChild("KritaDocument"); + if(kritadocument) { + Kross::Api::QtObject* kritadocumentqt = (Kross::Api::QtObject*)( kritadocument.data() ); + if(kritadocumentqt) { + ::KisDoc* document = (::KisDoc*)( kritadocumentqt->getObject() ); + if(document) { + addChild( new Doc(document) ); + } else { + throw Kross::Api::Exception::Ptr( new Kross::Api::Exception("There was no 'KritaDocument' published.") ); + } + } + } + // Wrap KritaScriptProgress + QString packagePath; + Kross::Api::Object::Ptr kritascriptprogress = manager->getChild("KritaScriptProgress"); + if(kritadocument) { + Kross::Api::QtObject* kritascriptprogressqt = (Kross::Api::QtObject*)( kritascriptprogress.data() ); + if(kritascriptprogressqt) { + ::KisScriptProgress* scriptprogress = (::KisScriptProgress*)( kritascriptprogressqt->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 'KritaScriptProgress' published.") ); + } + } + } + m_factory = new KritaCoreFactory(packagePath); +} + +KritaCoreModule::~KritaCoreModule() +{ + if(m_factory) + delete m_factory; +} + + +const QString KritaCoreModule::getClassName() const +{ + return "Kross::KritaCore::KritaCoreModule"; +} + +Kross::Api::Object::Ptr KritaCoreModule::call(const QString& name, Kross::Api::List::Ptr arguments) +{ + kdDebug(41011) << "KritaCoreModule::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/krita/plugins/viewplugins/scripting/kritacore/kritacoremodule.h b/krita/plugins/viewplugins/scripting/kritacore/kritacoremodule.h new file mode 100644 index 00000000..97abc8b9 --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritacore/kritacoremodule.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 KritaCore { + /** + * This class contains functions use to create new Kross object in a script + */ + class KritaCoreFactory : public Kross::Api::Event + { + public: + KritaCoreFactory(QString 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 + * Krosskritacore::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 + * Krosskritacore::newRGBColor(255,0,0) # create a red color + * Krosskritacore::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 + * Krosskritacore::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 krita + * It takes one argument : + * - the name of the pattern + * + * For example (in ruby) : + * @code + * Krosskritacore::getPattern("Bricks") + * @endcode + */ + Kross::Api::Object::Ptr getPattern(Kross::Api::List::Ptr); + /** + * This function return a Brush taken from the list of ressources + * of krita + * It takes one argument : + * - the name of the pattern + * + * For example (in ruby) : + * @code + * Krosskritacore::getBrush("Circle (05)") + * @endcode + */ + Kross::Api::Object::Ptr getBrush(Kross::Api::List::Ptr); + /** + * This function return a Brush with a circular shape + * 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 + * Krosskritacore::newCircleBrush(10,20) # create a plain circle + * Krosskritacore::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 shape + * 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 + * Krosskritacore::newRectBrush(10,20) # create a plain rectangle + * Krosskritacore::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 krita + * It takes one argument : + * - the name of the filter + * + * For example (in ruby) : + * @code + * Krosskritacore::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: + QString m_packagePath; + }; + /** + * + */ + class KritaCoreModule : public Kross::Api::Module + { + public: + /** + * Constructor. + */ + KritaCoreModule(Kross::Api::Manager* manager); + + /** + * Destructor. + */ + virtual ~KritaCoreModule(); + + /// \see Kross::Api::Object::getClassName + virtual const QString getClassName() const; + virtual Kross::Api::Object::Ptr call(const QString& name, Kross::Api::List::Ptr arguments); + private: + Kross::Api::Manager* m_manager; + KritaCoreFactory* m_factory; + }; + + +}} + +#endif + diff --git a/krita/plugins/viewplugins/scripting/kritacore/krs_brush.cpp b/krita/plugins/viewplugins/scripting/kritacore/krs_brush.cpp new file mode 100644 index 00000000..a6ae513c --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritacore/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 KritaCore { + +Brush::Brush(KisBrush* brush, bool sharedBrush) : Kross::Api::Class("KritaBrush"), m_brush(brush), m_sharedBrush(sharedBrush) +{ +} + +Brush::~Brush() +{ + if(!m_sharedBrush) + { + delete m_brush; + } +} + +} + +} diff --git a/krita/plugins/viewplugins/scripting/kritacore/krs_brush.h b/krita/plugins/viewplugins/scripting/kritacore/krs_brush.h new file mode 100644 index 00000000..f31e877d --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritacore/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 KritaCore { + +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/krita/plugins/viewplugins/scripting/kritacore/krs_color.cpp b/krita/plugins/viewplugins/scripting/kritacore/krs_color.cpp new file mode 100644 index 00000000..e459b1cd --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritacore/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 KritaCore { + +Color::Color ( int x, int y, int z, QColor::Spec colorSpec ) + : Kross::Api::Class("KritaColor"), m_color(x,y,z,colorSpec) +{ +} + +Color::Color() + : Kross::Api::Class("KritaColor") +{ +} + +Color::~Color() +{ +} + + +} + +} diff --git a/krita/plugins/viewplugins/scripting/kritacore/krs_color.h b/krita/plugins/viewplugins/scripting/kritacore/krs_color.h new file mode 100644 index 00000000..8d46760b --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritacore/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 KritaCore { + +class Color : public Kross::Api::Class +{ + public: + Color ( int x, int y, int z, QColor::Spec colorSpec ); + Color (); + + ~Color(); + public: + inline const QString getClassName() const + { return "Kross::Krita::Color"; }; + inline QColor toQColor() { return m_color; }; + private: + QColor m_color; +}; + +} + +} + +#endif diff --git a/krita/plugins/viewplugins/scripting/kritacore/krs_doc.cpp b/krita/plugins/viewplugins/scripting/kritacore/krs_doc.cpp new file mode 100644 index 00000000..23dffabb --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritacore/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 KritaCore { + +Doc::Doc(::KisDoc* doc) : Kross::Api::Class("KritaDocument"), m_doc(doc) { + addFunction("getImage", &Doc::getImage); +} + +Doc::~Doc() { + +} + +const QString Doc::getClassName() const { + return "Kross::KritaCore::Doc"; +} + +Kross::Api::Object::Ptr Doc::getImage(Kross::Api::List::Ptr) +{ + return new Image(m_doc->currentImage(), m_doc); +} + +} +} diff --git a/krita/plugins/viewplugins/scripting/kritacore/krs_doc.h b/krita/plugins/viewplugins/scripting/kritacore/krs_doc.h new file mode 100644 index 00000000..16336f94 --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritacore/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 KritaCore { + +class Doc : public Kross::Api::Class +{ + public: + explicit Doc(::KisDoc* doc); + virtual ~Doc(); + virtual const QString getClassName() const; + private: + /** + * This function return the Image associated with this Doc. + * + * Example (in Ruby) : + * @code + * doc = krosskritacore::get("KritaDocument") + * image = doc.getImage() + * @endcode + */ + Kross::Api::Object::Ptr getImage(Kross::Api::List::Ptr); + private: + KisDoc* m_doc; + +}; +} +} + + +#endif diff --git a/krita/plugins/viewplugins/scripting/kritacore/krs_filter.cpp b/krita/plugins/viewplugins/scripting/kritacore/krs_filter.cpp new file mode 100644 index 00000000..ee11d35d --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritacore/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 KritaCore { + +Filter::Filter(KisFilter* filter) + : Kross::Api::Class("KritaFilter"), m_filter(filter), m_config( new FilterConfiguration(filter->configuration()) ) +{ + addFunction("process", &Filter::process); + addFunction("getFilterConfiguration", &Filter::getFilterConfiguration); + +} + +Filter::~Filter() +{ +} + +const QString Filter::getClassName() const { + return "Kross::KritaCore::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").arg("process") ) ); + } + QRect 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 = QRect(x, y, w, h); + } else { + QRect r1 = src->paintLayer()->paintDevice()->extent(); + QRect 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/krita/plugins/viewplugins/scripting/kritacore/krs_filter.h b/krita/plugins/viewplugins/scripting/kritacore/krs_filter.h new file mode 100644 index 00000000..62554ef9 --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritacore/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 KritaCore { + 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 = Krosskritacore::get("KritaDocument") + * image = doc.getImage() + * layer = image.getActivePaintLayer() + * width = layer.getWidth() + * height = layer.getHeight() + * filter = Krosskritacore::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 QString getClassName() const; + private: + KisFilter* m_filter; + FilterConfiguration* m_config; +}; + +} +} + +#endif diff --git a/krita/plugins/viewplugins/scripting/kritacore/krs_filter_configuration.cpp b/krita/plugins/viewplugins/scripting/kritacore/krs_filter_configuration.cpp new file mode 100644 index 00000000..3479cf38 --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritacore/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 KritaCore { + + FilterConfiguration::FilterConfiguration(KisFilterConfiguration* fConfig) + : Kross::Api::Class("KritaFilterConfiguration"), m_fConfig(fConfig) +{ + addFunction("setProperty", &FilterConfiguration::setProperty); + addFunction("getProperty", &FilterConfiguration::getProperty); + addFunction("fromXML", &FilterConfiguration::fromXML); +} + +FilterConfiguration::~FilterConfiguration() +{ +} + +const QString FilterConfiguration::getClassName() const { + return "Kross::KritaCore::FilterConfiguration"; +} + + +Kross::Api::Object::Ptr FilterConfiguration::setProperty(Kross::Api::List::Ptr args) +{ + QString name = Kross::Api::Variant::toString(args->item(0)); + QVariant 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) +{ + QString name = Kross::Api::Variant::toString(args->item(0)); + QVariant 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) +{ + QString xml = Kross::Api::Variant::toString(args->item(0)); + m_fConfig->fromXML( xml ); + return 0; +} + +} +} diff --git a/krita/plugins/viewplugins/scripting/kritacore/krs_filter_configuration.h b/krita/plugins/viewplugins/scripting/kritacore/krs_filter_configuration.h new file mode 100644 index 00000000..7c8c3020 --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritacore/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 KritaCore { + +/** + @author Cyrille Berger +*/ +class FilterConfiguration : public Kross::Api::Class +{ + public: + FilterConfiguration(KisFilterConfiguration*); + ~FilterConfiguration(); + public: + virtual const QString 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/krita/plugins/viewplugins/scripting/kritacore/krs_histogram.cpp b/krita/plugins/viewplugins/scripting/kritacore/krs_histogram.cpp new file mode 100644 index 00000000..953eb868 --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritacore/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 KritaCore { + +Histogram::Histogram(KisPaintLayerSP layer, + KisHistogramProducerSP producer, + const enumHistogramType type) + : Kross::Api::Class("KritaHistogram") +{ + 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 QString Histogram::getClassName() const { + return "Kross::KritaCore::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/krita/plugins/viewplugins/scripting/kritacore/krs_histogram.h b/krita/plugins/viewplugins/scripting/kritacore/krs_histogram.h new file mode 100644 index 00000000..b238c5db --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritacore/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 KritaCore { + +/** + * This class allow to access the histogram of a PaintLayer. + * + * Example (in Ruby) : + * @code + * doc = krosskritacore::get("KritaDocument") + * 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 QString 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/krita/plugins/viewplugins/scripting/kritacore/krs_image.cpp b/krita/plugins/viewplugins/scripting/kritacore/krs_image.cpp new file mode 100644 index 00000000..b274ad33 --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritacore/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 KritaCore { + + Image::Image(KisImageSP image, KisDoc* doc) + : Kross::Api::Class("KritaImage"), 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 QString Image::getClassName() const { + return "Kross::KritaCore::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.").arg(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) +{ + QString name = Kross::Api::Variant::toString(args->item(0)); + int opacity = Kross::Api::Variant::toInt(args->item(1)); + opacity = CLAMP(opacity, 0, 255); + QString 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/krita/plugins/viewplugins/scripting/kritacore/krs_image.h b/krita/plugins/viewplugins/scripting/kritacore/krs_image.h new file mode 100644 index 00000000..0be2e46f --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritacore/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 KritaCore { + +class Image : public Kross::Api::Class +{ + public: + Image(KisImageSP image, KisDoc* doc = 0); + ~Image(); + virtual const QString 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/krita/plugins/viewplugins/scripting/kritacore/krs_iterator.h b/krita/plugins/viewplugins/scripting/kritacore/krs_iterator.h new file mode 100644 index 00000000..9493f49a --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritacore/krs_iterator.h @@ -0,0 +1,306 @@ +/* + * 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 KritaCore { + +// stupid Qt which doesn't support templated QObject +class IteratorMemoryManaged { + public: + virtual void invalidateIterator() = 0; +}; + +class IteratorMemoryManager : public QObject { + Q_OBJECT + public: + IteratorMemoryManager(IteratorMemoryManaged* it) : m_it(it) + { + // Connect the Monitor to know when the invalidating of iterator is needed + connect(KisScriptMonitor::instance(), SIGNAL(executionFinished(const Kross::Api::ScriptAction* )), this, SLOT(invalidateIterator())); + + } + public slots: + void invalidateIterator() + { + m_it->invalidateIterator(); + } + 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 >("KritaIterator"), 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 + QValueVector channels = layer->paintDevice()->colorSpace()->channels(); + QString initiales = ""; + for(QValueVector::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() + { + invalidateIterator(); + delete m_itmm; + } + virtual const QString getClassName() const { + return "Kross::KritaCore::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) + { + Q_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) + { + Q_UINT8* data = (Q_UINT8*)(m_it->rawData() + channelpos); + return new Kross::Api::Variant( * data); + } + Kross::Api::Object::Ptr setChannelUINT8(Kross::Api::List::Ptr args, uint channelpos) + { + Q_UINT8* data = (Q_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) + { + Q_UINT16* data = (Q_UINT16*)(m_it->rawData() + channelpos); + return new Kross::Api::Variant( * data); + } + Kross::Api::Object::Ptr setChannelUINT16(Kross::Api::List::Ptr args, uint channelpos) + { + Q_UINT16* data = (Q_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) + { + QValueVector channels = m_layer->paintDevice()->colorSpace()->channels(); + QValueList pixel; + for(QValueVector::iterator itC = channels.begin(); itC != channels.end(); itC++) + { + KisChannelInfo * ci = *itC; + Q_UINT8* data = (Q_UINT8*)(m_it->rawData() + ci->pos()); + switch(ci->channelValueType()) + { + case KisChannelInfo::UINT8: + pixel.push_back( *data); + break; + case KisChannelInfo::UINT16: + pixel.push_back( *((Q_UINT16*) data) ); + break; + case KisChannelInfo::FLOAT32: + pixel.push_back( *((float*) data) ); + break; + default: + kdDebug(41011) << i18n("An error has occurred in %1").arg("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) + { + QValueList pixel = Kross::Api::Variant::toList( args->item(0) ); + QValueVector channels = m_layer->paintDevice()->colorSpace()->channels(); + uint i = 0; + for(QValueVector::iterator itC = channels.begin(); itC != channels.end(); itC++, i++) + { + KisChannelInfo * ci = *itC; + Q_UINT8* data = (Q_UINT8*)(m_it->rawData() + ci->pos()); + switch(ci->channelValueType()) + { + case KisChannelInfo::UINT8: + *data = pixel[i].toUInt(); + break; + case KisChannelInfo::UINT16: + *((Q_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").arg("setPixel") << endl; + kdDebug(41011) << i18n("unsupported data format in scripts") << endl; + break; + } + } + return 0; + } + private: + virtual void invalidateIterator() + { + 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/krita/plugins/viewplugins/scripting/kritacore/krs_paint_layer.cpp b/krita/plugins/viewplugins/scripting/kritacore/krs_paint_layer.cpp new file mode 100644 index 00000000..1f79b22c --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritacore/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 KritaCore { + +PaintLayer::PaintLayer(KisPaintLayerSP layer, KisDoc* doc) + : Kross::Api::Class("KritaLayer"), 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 QString PaintLayer::getClassName() const { + return "Kross::KritaCore::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) +{ + QRect r1 = paintLayer()->extent(); + QRect r2 = paintLayer()->image()->bounds(); + QRect rect = r1.intersect(r2); + return new Kross::Api::Variant(rect.width()); +} +Kross::Api::Object::Ptr PaintLayer::getHeight(Kross::Api::List::Ptr) +{ + QRect r1 = paintLayer()->extent(); + QRect r2 = paintLayer()->image()->bounds(); + QRect rect = r1.intersect(r2); + return new Kross::Api::Variant(rect.height()); +} + +Kross::Api::Object::Ptr PaintLayer::createHistogram(Kross::Api::List::Ptr args) +{ + QString 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").arg("createHistogram") + "\n" + i18n("The histogram %1 is not available").arg(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) +{ + QString 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").arg("convertToColorspace") + "\n" + i18n("Colorspace %1 is not available, please check your installation.").arg(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() ); + QRect 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() ); + QRect rect = paintLayer()->exactBounds(); + mathToolbox->fastWaveletUntransformation( paintLayer()->paintDevice(), rect, wav->wavelet() ); + return 0; +} + + +} + +} diff --git a/krita/plugins/viewplugins/scripting/kritacore/krs_paint_layer.h b/krita/plugins/viewplugins/scripting/kritacore/krs_paint_layer.h new file mode 100644 index 00000000..4ddfd4bd --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritacore/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 KritaCore { + +/** +@author Cyrille Berger +*/ +class PaintLayer : public Kross::Api::Class +{ + public: + explicit PaintLayer(KisPaintLayerSP layer, KisDoc* doc = 0); + virtual ~PaintLayer(); + virtual const QString 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/krita/plugins/viewplugins/scripting/kritacore/krs_painter.cpp b/krita/plugins/viewplugins/scripting/kritacore/krs_painter.cpp new file mode 100644 index 00000000..621a173d --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritacore/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 KritaCore { + +Painter::Painter(KisPaintLayerSP layer) + : Kross::Api::Class("KritaPainter"), 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()); + QRect 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 = QRect(x,y,w,h); + } else { + QRect r1 = paintLayer()->paintDevice()->extent(); + QRect r2 = paintLayer()->image()->bounds(); + rect = r1.intersect(r2); + } + + QValueList kernelH = Kross::Api::Variant::toList( args->item(0) ); + + QVariant firstlineVariant = *kernelH.begin(); + if(firstlineVariant.type() != QVariant::List) + { + throw Kross::Api::Exception::Ptr( new Kross::Api::Exception(i18n("An error has occured in %1").arg("applyConvolution")) ); + } + + QValueList firstline = firstlineVariant.toList(); + + kernel.height = kernelH.size(); + kernel.width = firstline.size(); + + kernel.data = new Q_INT32[kernel.height * kernel.width]; + + uint i = 0; + for(QValueList::iterator itK = kernelH.begin(); itK != kernelH.end(); itK++, i ++ ) + { + QVariant lineVariant = *kernelH.begin(); + if(lineVariant.type() != QVariant::List) + { + throw Kross::Api::Exception::Ptr( new Kross::Api::Exception(i18n("An error has occured in %1").arg("applyConvolution")) ); + } + QValueList line = firstlineVariant.toList(); + if(line.size() != kernel.width) + { + throw Kross::Api::Exception::Ptr( new Kross::Api::Exception(i18n("An error has occured in %1").arg("applyConvolution")) ); + } + uint j = 0; + for(QValueList::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) +{ + Q_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) +{ + QValueList pointsX = Kross::Api::Variant::toList( args->item(0) ); + QValueList 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) +{ + QValueList pointsX = Kross::Api::Variant::toList( args->item(0) ); + QValueList 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->toQColor(), 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->toQColor(), 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) +{ + QString 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/krita/plugins/viewplugins/scripting/kritacore/krs_painter.h b/krita/plugins/viewplugins/scripting/kritacore/krs_painter.h new file mode 100644 index 00000000..37ae7993 --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritacore/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 KritaCore { + +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( QValueList xs, QValueList ys) + { + vKisPoint a; + QValueList::iterator itx = xs.begin(); + QValueList::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/krita/plugins/viewplugins/scripting/kritacore/krs_pattern.cpp b/krita/plugins/viewplugins/scripting/kritacore/krs_pattern.cpp new file mode 100644 index 00000000..8b89c8a7 --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritacore/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 KritaCore { + +Pattern::Pattern(KisPattern* pattern, bool sharedPattern) : Kross::Api::Class("KritaPattern"), m_pattern(pattern), m_sharedPattern(sharedPattern) +{ +} + +Pattern::~Pattern() +{ + if(!m_sharedPattern) + delete m_pattern; +} + +} + +} diff --git a/krita/plugins/viewplugins/scripting/kritacore/krs_pattern.h b/krita/plugins/viewplugins/scripting/kritacore/krs_pattern.h new file mode 100644 index 00000000..f7dd7e35 --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritacore/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 KritaCore { + +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/krita/plugins/viewplugins/scripting/kritacore/krs_script_progress.cpp b/krita/plugins/viewplugins/scripting/kritacore/krs_script_progress.cpp new file mode 100644 index 00000000..e653f12a --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritacore/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 KritaCore { + +ScriptProgress::ScriptProgress(KisScriptProgress* script): Kross::Api::Class("KritaScript"), 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/krita/plugins/viewplugins/scripting/kritacore/krs_script_progress.h b/krita/plugins/viewplugins/scripting/kritacore/krs_script_progress.h new file mode 100644 index 00000000..535485cb --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritacore/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 KritaCore { + +/** + * ScriptProgress is used to manage the progress bar of the status bar in krita + * + * For example (in ruby) : + * @code + * script = Krosskritacore::get("KritaScript") + * 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/krita/plugins/viewplugins/scripting/kritacore/krs_wavelet.cpp b/krita/plugins/viewplugins/scripting/kritacore/krs_wavelet.cpp new file mode 100644 index 00000000..d2786780 --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritacore/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 KritaCore { + +Wavelet::Wavelet(KisMathToolbox::KisWavelet* kwl) + : Kross::Api::Class("KritaWavelet"), 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) +{ + Q_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").arg("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) +{ + Q_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").arg("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) +{ + Q_UINT32 x = Kross::Api::Variant::toUInt(args->item(0)); + Q_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").arg("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) +{ + Q_UINT32 x = Kross::Api::Variant::toUInt(args->item(0)); + Q_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").arg("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/krita/plugins/viewplugins/scripting/kritacore/krs_wavelet.h b/krita/plugins/viewplugins/scripting/kritacore/krs_wavelet.h new file mode 100644 index 00000000..bee73e9b --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritacore/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 KritaCore { + +/** + @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/krita/plugins/viewplugins/scripting/kritascripting.desktop b/krita/plugins/viewplugins/scripting/kritascripting.desktop new file mode 100644 index 00000000..cfdbbbf4 --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritascripting.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=Krita/ViewPlugin +Type=Service +X-KDE-Library=kritascripting +X-Krita-Version=2 diff --git a/krita/plugins/viewplugins/scripting/kritascripting/Makefile.am b/krita/plugins/viewplugins/scripting/kritascripting/Makefile.am new file mode 100644 index 00000000..76dc7ea5 --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritascripting/Makefile.am @@ -0,0 +1,19 @@ +INCLUDES = -I$(top_srcdir)/krita/sdk \ + -I$(top_srcdir)/krita/core \ + -I$(top_srcdir)/krita/kritacolor/ \ + -I$(top_srcdir)/krita/ui \ + $(KROSS_INCLUDES) \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + + +lib_LTLIBRARIES = libkritascripting.la +libkritascripting_la_SOURCES = kis_script_progress.cpp kis_script_monitor.cpp +noinst_HEADERS = kis_script_progress.h + +libkritascripting_la_LDFLAGS = -no-undefined $(all_libraries) +libkritascripting_la_LIBADD = $(top_builddir)/krita/libkritacommon.la $(top_builddir)/lib/kross/main/libkrossmain.la + +KDE_CXXFLAGS = $(USE_EXCEPTIONS) + +libkritascripting_la_METASOURCES = AUTO diff --git a/krita/plugins/viewplugins/scripting/kritascripting/kis_script_monitor.cpp b/krita/plugins/viewplugins/scripting/kritascripting/kis_script_monitor.cpp new file mode 100644 index 00000000..8bb12596 --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritascripting/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, SIGNAL(executionFinished( const Kross::Api::ScriptAction* )), SIGNAL(executionFinished( const Kross::Api::ScriptAction* ))); + connect(guiClient, SIGNAL(executionStarted( const Kross::Api::ScriptAction* )), 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/krita/plugins/viewplugins/scripting/kritascripting/kis_script_monitor.h b/krita/plugins/viewplugins/scripting/kritascripting/kis_script_monitor.h new file mode 100644 index 00000000..de1e0380 --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritascripting/kis_script_monitor.h @@ -0,0 +1,50 @@ +/* + * 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 QObject { + Q_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/krita/plugins/viewplugins/scripting/kritascripting/kis_script_progress.cpp b/krita/plugins/viewplugins/scripting/kritascripting/kis_script_progress.cpp new file mode 100644 index 00000000..c3629304 --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritascripting/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(Q_INT32 totalSteps) +{ + m_progressTotalSteps = totalSteps; + m_progressSteps = 0; + m_lastProgressPerCent = 0; + emit notifyProgress(0); +} + +void KisScriptProgress::setProgress(Q_INT32 progress) +{ + m_progressSteps = progress; + Q_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 QString& stage, Q_INT32 progress) +{ + Q_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/krita/plugins/viewplugins/scripting/kritascripting/kis_script_progress.h b/krita/plugins/viewplugins/scripting/kritascripting/kis_script_progress.h new file mode 100644 index 00000000..864a6760 --- /dev/null +++ b/krita/plugins/viewplugins/scripting/kritascripting/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(Q_INT32 totalSteps); + void setProgress(Q_INT32 progress); + void incProgress(); + void setProgressStage(const QString& stage, Q_INT32 progress); + void progressDone(); + inline void setPackagePath(QString path) { m_packagePath = path; }; + inline QString packagePath() { return m_packagePath; } + private: + Q_INT32 m_progressSteps, m_progressTotalSteps, m_lastProgressPerCent; + KisView * m_view; + QString m_packagePath; +}; + +#endif diff --git a/krita/plugins/viewplugins/scripting/samples/Makefile.am b/krita/plugins/viewplugins/scripting/samples/Makefile.am new file mode 100644 index 00000000..1eebb4c7 --- /dev/null +++ b/krita/plugins/viewplugins/scripting/samples/Makefile.am @@ -0,0 +1,3 @@ +INCLUDES = -I$(srcdir)/../../../sdk -I$(srcdir)/../../../core -I$(srcdir)/../../../kritacolor/ -I$(srcdir)/../../../ui -I$(top_srcdir)/kexi/scriptingcore/main $(KOFFICE_INCLUDES) $(all_includes) +METASOURCES = AUTO +SUBDIRS = python ruby diff --git a/krita/plugins/viewplugins/scripting/samples/python/Makefile.am b/krita/plugins/viewplugins/scripting/samples/python/Makefile.am new file mode 100644 index 00000000..5b1f28f3 --- /dev/null +++ b/krita/plugins/viewplugins/scripting/samples/python/Makefile.am @@ -0,0 +1,5 @@ +scriptinvertdir = $(kde_datadir)/krita/scripts/invertpython +scriptinvert_SCRIPTS = invert.py invertpython.rc + +scriptreshapedir = $(kde_datadir)/krita/scripts/reshapehisto +scriptreshape_SCRIPTS = reshapehisto.py reshapehisto.rc diff --git a/krita/plugins/viewplugins/scripting/samples/python/invert.py b/krita/plugins/viewplugins/scripting/samples/python/invert.py new file mode 100644 index 00000000..2c87593d --- /dev/null +++ b/krita/plugins/viewplugins/scripting/samples/python/invert.py @@ -0,0 +1,48 @@ +# This file is part of Krita +# +# 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 krosskritacore + except: + raise "Import of the KritaCore module failed." + doc = krosskritacore.get("KritaDocument") + script = krosskritacore.get("KritaScript") + 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/krita/plugins/viewplugins/scripting/samples/python/invertpython.rc b/krita/plugins/viewplugins/scripting/samples/python/invertpython.rc new file mode 100644 index 00000000..d2224311 --- /dev/null +++ b/krita/plugins/viewplugins/scripting/samples/python/invertpython.rc @@ -0,0 +1,9 @@ + + + diff --git a/krita/plugins/viewplugins/scripting/samples/python/reshapehisto.py b/krita/plugins/viewplugins/scripting/samples/python/reshapehisto.py new file mode 100644 index 00000000..4a79e68c --- /dev/null +++ b/krita/plugins/viewplugins/scripting/samples/python/reshapehisto.py @@ -0,0 +1,300 @@ +# This file is part of Krita +# +# 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 krosskritacore +except: + raise "Import of the KritaCore 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 = krosskritacore.get("KritaDocument") +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/krita/plugins/viewplugins/scripting/samples/python/reshapehisto.rc b/krita/plugins/viewplugins/scripting/samples/python/reshapehisto.rc new file mode 100644 index 00000000..481f5764 --- /dev/null +++ b/krita/plugins/viewplugins/scripting/samples/python/reshapehisto.rc @@ -0,0 +1,9 @@ + + + diff --git a/krita/plugins/viewplugins/scripting/samples/ruby/Makefile.am b/krita/plugins/viewplugins/scripting/samples/ruby/Makefile.am new file mode 100644 index 00000000..2aa79416 --- /dev/null +++ b/krita/plugins/viewplugins/scripting/samples/ruby/Makefile.am @@ -0,0 +1,18 @@ +scriptsinvertdir = $(kde_datadir)/krita/scripts/invertruby +scriptsinvert_SCRIPTS = invert.rb invertruby.rc + +scriptschangecsdir = $(kde_datadir)/krita/scripts/changecs +scriptschangecs_SCRIPTS = changecs.rb changecs.rc + +scriptsrandompaintdir = $(kde_datadir)/krita/scripts/randompaint +scriptsrandompaint_SCRIPTS = randompaint.rb randompaint.rc + +scriptsfilterstestdir = $(kde_datadir)/krita/scripts/filterstest +scriptsfilterstest_SCRIPTS = filterstest.rb filterstest.rc + +scriptstorturefiltersdir = $(kde_datadir)/krita/scripts/torturefilters +scriptstorturefilters_SCRIPTS = torture-filters.rb torture-filters.rc + +scriptstorturepaintingdir = $(kde_datadir)/krita/scripts/torturepainting +scriptstorturepainting_SCRIPTS = torture-painting.rb torture-painting.rc + diff --git a/krita/plugins/viewplugins/scripting/samples/ruby/changecs.rb b/krita/plugins/viewplugins/scripting/samples/ruby/changecs.rb new file mode 100644 index 00000000..f5d99a3f --- /dev/null +++ b/krita/plugins/viewplugins/scripting/samples/ruby/changecs.rb @@ -0,0 +1,5 @@ +require "krosskritacore" + +doc = Krosskritacore::get("KritaDocument") +image = doc.getImage() +image.convertToColorspace("LABA") diff --git a/krita/plugins/viewplugins/scripting/samples/ruby/changecs.rc b/krita/plugins/viewplugins/scripting/samples/ruby/changecs.rc new file mode 100644 index 00000000..4121693d --- /dev/null +++ b/krita/plugins/viewplugins/scripting/samples/ruby/changecs.rc @@ -0,0 +1,9 @@ + + + diff --git a/krita/plugins/viewplugins/scripting/samples/ruby/filterstest.rb b/krita/plugins/viewplugins/scripting/samples/ruby/filterstest.rb new file mode 100644 index 00000000..20d42dbf --- /dev/null +++ b/krita/plugins/viewplugins/scripting/samples/ruby/filterstest.rb @@ -0,0 +1,31 @@ +# This file is part of Krita +# +# 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 "krosskritacore" + +doc = Krosskritacore::get("KritaDocument") + +image = doc.getImage() +layer = image.getActivePaintLayer() +width = layer.getWidth() +height = layer.getHeight() + +filter = Krosskritacore::getFilter("invert") + +filter.process(layer ) +filter.process(layer, 10, 10, 20, 20 ) diff --git a/krita/plugins/viewplugins/scripting/samples/ruby/filterstest.rc b/krita/plugins/viewplugins/scripting/samples/ruby/filterstest.rc new file mode 100644 index 00000000..2f8dfb98 --- /dev/null +++ b/krita/plugins/viewplugins/scripting/samples/ruby/filterstest.rc @@ -0,0 +1,9 @@ + + + diff --git a/krita/plugins/viewplugins/scripting/samples/ruby/invert.rb b/krita/plugins/viewplugins/scripting/samples/ruby/invert.rb new file mode 100644 index 00000000..0a055028 --- /dev/null +++ b/krita/plugins/viewplugins/scripting/samples/ruby/invert.rb @@ -0,0 +1,45 @@ +# This file is part of Krita +# +# 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 "krosskritacore" + +doc = Krosskritacore::get("KritaDocument") +script = Krosskritacore::get("KritaScript") +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/krita/plugins/viewplugins/scripting/samples/ruby/invertruby.rc b/krita/plugins/viewplugins/scripting/samples/ruby/invertruby.rc new file mode 100644 index 00000000..9cc7bd6a --- /dev/null +++ b/krita/plugins/viewplugins/scripting/samples/ruby/invertruby.rc @@ -0,0 +1,9 @@ + + + diff --git a/krita/plugins/viewplugins/scripting/samples/ruby/randompaint.rb b/krita/plugins/viewplugins/scripting/samples/ruby/randompaint.rb new file mode 100644 index 00000000..9e2f504f --- /dev/null +++ b/krita/plugins/viewplugins/scripting/samples/ruby/randompaint.rb @@ -0,0 +1,98 @@ +def randomizeStyle(painter) + painter.setFillStyle(4 *rand) + painter.setStrokeStyle(2 *rand) +end + +require "krosskritacore" + +doc = Krosskritacore::get("KritaDocument") +script = Krosskritacore::get("KritaScript") + +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 = Krosskritacore::newRGBColor(0,0,0) + +# set painting color +painter.setPaintColor( blackcolor ) + +# get the brush +brush = Krosskritacore::getBrush("Circle (05)") + +# define the brush +painter.setBrush(brush) + +# get the pattern +pattern = Krosskritacore::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( Krosskritacore::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( Krosskritacore::newRGBColor(rand*255,rand*255,rand*255) ) + painter.setBackgroundColor( Krosskritacore::newRGBColor(rand*255,rand*255,rand*255) ) + painter.setOpacity( rand*255 ) +# set the brush + if(rand < 0.5) + painter.setBrush( Krosskritacore::newRectBrush(rand*20,rand*20,rand*10,rand*10) ) + else + painter.setBrush( Krosskritacore::newCircleBrush(rand*20,rand*20,rand*10,rand*10) ) + end + # paint a point + shape = rand * 7 + painter.setStrokeStyle(1) + if( shape < 1 ) + painter.paintAt(rand * width , rand * height,1.1) + elsif(shape < 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(shape < 3) + painter.paintLine(rand * width, rand * height, 1.1, rand * width, rand * height,1.1) + elsif(shape < 4) + painter.paintBezierCurve(rand * width, rand * height, 1.1, rand * width, rand * height, rand * width , rand * height, rand * width, rand * height, 1.1) + elsif(shape < 5) + randomizeStyle(painter) + painter.paintEllipse(rand * width, rand * height, rand * width, rand * height, 1.1) + elsif(shape < 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(shape < 7) + randomizeStyle(painter) + painter.paintRect(rand * width, rand * height, rand * width, rand * height, 1.1) + end + script.incProgress() +end + +layer.endPainting() diff --git a/krita/plugins/viewplugins/scripting/samples/ruby/randompaint.rc b/krita/plugins/viewplugins/scripting/samples/ruby/randompaint.rc new file mode 100644 index 00000000..3697f700 --- /dev/null +++ b/krita/plugins/viewplugins/scripting/samples/ruby/randompaint.rc @@ -0,0 +1,9 @@ + + + diff --git a/krita/plugins/viewplugins/scripting/samples/ruby/torture-filters.rb b/krita/plugins/viewplugins/scripting/samples/ruby/torture-filters.rb new file mode 100644 index 00000000..58cddcd6 --- /dev/null +++ b/krita/plugins/viewplugins/scripting/samples/ruby/torture-filters.rb @@ -0,0 +1,70 @@ +# This file is part of Krita +# +# 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 "krosskritacore" + +doc = Krosskritacore::get("KritaDocument") + +image = doc.getImage() +layer = image.getActivePaintLayer() + +def testFilter(layer, filterid) + print " applying filter ", filterid, "\n" + begin + filter = Krosskritacore::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/krita/plugins/viewplugins/scripting/samples/ruby/torture-filters.rc b/krita/plugins/viewplugins/scripting/samples/ruby/torture-filters.rc new file mode 100644 index 00000000..c56c2818 --- /dev/null +++ b/krita/plugins/viewplugins/scripting/samples/ruby/torture-filters.rc @@ -0,0 +1,9 @@ + + + diff --git a/krita/plugins/viewplugins/scripting/samples/ruby/torture-painting.rb b/krita/plugins/viewplugins/scripting/samples/ruby/torture-painting.rb new file mode 100644 index 00000000..67042de2 --- /dev/null +++ b/krita/plugins/viewplugins/scripting/samples/ruby/torture-painting.rb @@ -0,0 +1,133 @@ +# This file is part of Krita +# +# 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 "krosskritacore" + +class TorturePainting + + def initialize() + + doc = Krosskritacore::get("KritaDocument") + @script = Krosskritacore::get("KritaScript") + + @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 = Krosskritacore::newRGBColor(0,0,0) + + # set painting color + painter.setPaintColor( blackcolor ) + + # get the pattern + pattern = Krosskritacore::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( Krosskritacore::newRGBColor(rand*255,rand*255,rand*255) ) + painter.setBackgroundColor( Krosskritacore::newRGBColor(rand*255,rand*255,rand*255) ) + painter.setOpacity( rand*255 ) + # set the brush + if(rand < 0.5) + painter.setBrush( Krosskritacore::newRectBrush(rand*20,rand*20,rand*10,rand*10) ) + else + painter.setBrush( Krosskritacore::newCircleBrush(rand*20,rand*20,rand*10,rand*10) ) + end + # paint a point + shape = rand * 7 + painter.setStrokeStyle(1) + if( shape < 1 ) + painter.paintAt(rand * @width , rand * @height,1.1) + elsif(shape < 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(shape < 3) + painter.paintLine(rand * @width, rand * @height, 1.1, rand * @width, rand * @height,1.1) + elsif(shape < 4) + painter.paintBezierCurve(rand * @width, rand * @height, 1.1, rand * @width, rand * @height, rand * @width , rand * @height, rand * @width, rand * @height, 1.1) + elsif(shape < 5) + randomizeStyle(painter) + painter.paintEllipse(rand * @width, rand * @height, rand * @width, rand * @height, 1.1) + elsif(shape < 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(shape < 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/krita/plugins/viewplugins/scripting/samples/ruby/torture-painting.rc b/krita/plugins/viewplugins/scripting/samples/ruby/torture-painting.rc new file mode 100644 index 00000000..6b54fa9d --- /dev/null +++ b/krita/plugins/viewplugins/scripting/samples/ruby/torture-painting.rc @@ -0,0 +1,9 @@ + + + diff --git a/krita/plugins/viewplugins/scripting/scripting.cc b/krita/plugins/viewplugins/scripting/scripting.cc new file mode 100644 index 00000000..d7f5fde7 --- /dev/null +++ b/krita/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 "kritascripting/kis_script_progress.h" +#include "kritascripting/kis_script_monitor.h" + +typedef KGenericFactory KritaScriptingFactory; +K_EXPORT_COMPONENT_FACTORY( kritascripting, KritaScriptingFactory( "krita" ) ) + +Scripting::Scripting(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(KritaScriptingFactory::instance()); + + + if ( parent->inherits("KisView") ) + { + setInstance(Scripting::instance()); + m_view = (KisView*) parent; + m_scriptguiclient = new Kross::Api::ScriptGUIClient( m_view, m_view ); +// m_scriptguiclient ->setXMLFile(locate("data","kritaplugins/scripting.rc"), true); + //BEGIN TODO: understand why the ScriptGUIClient doesn't "link" its actions to the menu + setXMLFile(locate("data","kritaplugins/scripting.rc"), true); + new KAction(i18n("Execute Script File..."), 0, 0, m_scriptguiclient, SLOT(executeScriptFile()), actionCollection(), "executescriptfile"); + new KAction(i18n("Script Manager..."), 0, 0, m_scriptguiclient, SLOT(showScriptManager()), actionCollection(), "configurescripts"); + //END TODO + + QWidget * w = new Kross::Api::WdgScriptsManager(m_scriptguiclient, m_view); + + m_view->canvasSubject()->paletteManager()->addWidget(w, "Scripts Manager", krita::LAYERBOX, 10, PALETTE_DOCKER, false); + + connect(m_scriptguiclient, SIGNAL(executionFinished( const Kross::Api::ScriptAction* )), this, SLOT(executionFinished(const Kross::Api::ScriptAction*))); + connect(m_scriptguiclient, SIGNAL(executionStarted( const Kross::Api::ScriptAction* )), this, SLOT(executionStarted(const Kross::Api::ScriptAction*))); + KisScriptMonitor::instance()->monitor( m_scriptguiclient ); + + Kross::Api::Manager::scriptManager()->addQObject(m_view->canvasSubject()->document(), "KritaDocument"); + Kross::Api::Manager::scriptManager()->addQObject(m_view, "KritaView"); + m_scriptProgress = new KisScriptProgress(m_view); + Kross::Api::Manager::scriptManager()->addQObject(m_scriptProgress, "KritaScriptProgress"); + + } + +} + +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(); + QApplication::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/krita/plugins/viewplugins/scripting/scripting.h b/krita/plugins/viewplugins/scripting/scripting.h new file mode 100644 index 00000000..238483c8 --- /dev/null +++ b/krita/plugins/viewplugins/scripting/scripting.h @@ -0,0 +1,53 @@ +/* + * This file is part of Krita + * + * 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 + public: + Scripting(QObject *parent, const char *name, const QStringList &); + 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/krita/plugins/viewplugins/scripting/scripting.rc b/krita/plugins/viewplugins/scripting/scripting.rc new file mode 100644 index 00000000..8d2ba496 --- /dev/null +++ b/krita/plugins/viewplugins/scripting/scripting.rc @@ -0,0 +1,10 @@ + + + + S&cripts + + + + + + diff --git a/krita/plugins/viewplugins/selectopaque/Makefile.am b/krita/plugins/viewplugins/selectopaque/Makefile.am new file mode 100644 index 00000000..2c382ce3 --- /dev/null +++ b/krita/plugins/viewplugins/selectopaque/Makefile.am @@ -0,0 +1,24 @@ +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = kritaselectopaque.la + +kritaselectopaque_la_SOURCES = selectopaque.cc +noinst_HEADERS = selectopaque.h + +kritaselectopaque_la_LIBADD = ../../../libkritacommon.la +kritaselectopaque_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) + +kritarcdir = $(kde_datadir)/kritaplugins +kritarc_DATA = selectopaque.rc +EXTRA_DIST = $(kritarc_DATA) + +kde_services_DATA = kritaselectopaque.desktop + +kritaselectopaque_la_METASOURCES = AUTO + +KDE_OPTIONS = nofinal diff --git a/krita/plugins/viewplugins/selectopaque/kritaselectopaque.desktop b/krita/plugins/viewplugins/selectopaque/kritaselectopaque.desktop new file mode 100644 index 00000000..69690306 --- /dev/null +++ b/krita/plugins/viewplugins/selectopaque/kritaselectopaque.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=Krita/ViewPlugin +Type=Service +X-KDE-Library=kritaselectopaque +X-Krita-Version=2 diff --git a/krita/plugins/viewplugins/selectopaque/selectopaque.cc b/krita/plugins/viewplugins/selectopaque/selectopaque.cc new file mode 100644 index 00000000..cfbcb4e7 --- /dev/null +++ b/krita/plugins/viewplugins/selectopaque/selectopaque.cc @@ -0,0 +1,116 @@ +/* + * selectopague.h -- Part of Krita + * + * 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( kritaselectopaque, SelectOpaqueFactory( "krita" ) ) + +SelectOpaque::SelectOpaque(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + + if (parent->inherits("KisView")) { + setInstance(SelectOpaqueFactory::instance()); + setXMLFile(locate("data","kritaplugins/selectopaque.rc"), true); + m_view = dynamic_cast(parent); + m_view->canvasSubject()->selectionManager()->addSelectionAction( new KAction(i18n("&Select All Opaque Pixels..."), 0, 0, this, SLOT(slotActivated()), actionCollection(), "selectopaque") ); + + } +} + +SelectOpaque::~SelectOpaque() +{ +} + +void SelectOpaque::slotActivated() +{ + KisSelectedTransaction *transaction; + + KisPaintDeviceSP layer = m_view->canvasSubject()->currentImg()->activeDevice(); + if (!layer) return; + QApplication::setOverrideCursor(KisCursor::waitCursor()); + + if (layer->image()->undo()) transaction = new KisSelectedTransaction(i18n("Select Opaque Pixels"), layer); + // XXX: Multithread this! + Q_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(); + } + QApplication::restoreOverrideCursor(); + layer->setDirty(); + layer->emitSelectionChanged(); + + if (layer->image()->undo()) m_view->canvasSubject()->undoAdapter()->addCommand(transaction); + +} + +#include "selectopaque.moc" + diff --git a/krita/plugins/viewplugins/selectopaque/selectopaque.h b/krita/plugins/viewplugins/selectopaque/selectopaque.h new file mode 100644 index 00000000..5215ecfe --- /dev/null +++ b/krita/plugins/viewplugins/selectopaque/selectopaque.h @@ -0,0 +1,44 @@ +/* + * selectopaque.h -- Part of Krita + * + * 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 + public: + SelectOpaque(QObject *parent, const char *name, const QStringList &); + virtual ~SelectOpaque(); + + private slots: + void slotActivated(); + + private: + KisView * m_view; + KisPainter * m_painter; + +}; + +#endif // SELECTOPAQUE_H diff --git a/krita/plugins/viewplugins/selectopaque/selectopaque.rc b/krita/plugins/viewplugins/selectopaque/selectopaque.rc new file mode 100644 index 00000000..1696d3d0 --- /dev/null +++ b/krita/plugins/viewplugins/selectopaque/selectopaque.rc @@ -0,0 +1,10 @@ + + + + Select + + + + + + diff --git a/krita/plugins/viewplugins/separate_channels/Makefile.am b/krita/plugins/viewplugins/separate_channels/Makefile.am new file mode 100644 index 00000000..238e4184 --- /dev/null +++ b/krita/plugins/viewplugins/separate_channels/Makefile.am @@ -0,0 +1,26 @@ +kritarcdir = $(kde_datadir)/kritaplugins +kritarc_DATA = imageseparate.rc +EXTRA_DIST = $(kritarc_DATA) + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = kritaseparatechannels.la + +kritaseparatechannels_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 = kritaseparatechannels.desktop + +kritaseparatechannels_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritaseparatechannels_la_LIBADD = ../../../libkritacommon.la + +kritaseparatechannels_la_METASOURCES = AUTO diff --git a/krita/plugins/viewplugins/separate_channels/dlg_separate.cc b/krita/plugins/viewplugins/separate_channels/dlg_separate.cc new file mode 100644 index 00000000..760786ec --- /dev/null +++ b/krita/plugins/viewplugins/separate_channels/dlg_separate.cc @@ -0,0 +1,110 @@ +/* + * dlg_separate.cc - part of KimageShop^WKrayon^WKrita + * + * 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 QString & imageCS, + const QString & layerCS, + QWidget * parent, + const char * name) + : super (parent, 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->sizeHint()); + + m_page->lblColormodel->setText(layerCS); + m_page->grpOutput->hide(); + connect(m_page->grpSource, SIGNAL(clicked(int)), this, SLOT(slotSetColorSpaceLabel(int))); + connect(m_page->chkColors, SIGNAL(toggled(bool)), m_page->chkDownscale, SLOT(setDisabled(bool))); + + connect(this, SIGNAL(okClicked()), + this, 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/krita/plugins/viewplugins/separate_channels/dlg_separate.h b/krita/plugins/viewplugins/separate_channels/dlg_separate.h new file mode 100644 index 00000000..08432014 --- /dev/null +++ b/krita/plugins/viewplugins/separate_channels/dlg_separate.h @@ -0,0 +1,67 @@ +/* + * dlg_imagesize.h -- part of KimageShop^WKrayon^WKrita + * + * 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 + +public: + + DlgSeparate(const QString & imageCS, const QString & layerCS, QWidget * parent = 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; + QString m_imageCS; + QString m_layerCS; + +}; + +#endif // DLG_SEPARATE diff --git a/krita/plugins/viewplugins/separate_channels/imageseparate.rc b/krita/plugins/viewplugins/separate_channels/imageseparate.rc new file mode 100644 index 00000000..4f587123 --- /dev/null +++ b/krita/plugins/viewplugins/separate_channels/imageseparate.rc @@ -0,0 +1,9 @@ + + + + Image + + + + + diff --git a/krita/plugins/viewplugins/separate_channels/kis_channel_separator.cc b/krita/plugins/viewplugins/separate_channels/kis_channel_separator.cc new file mode 100644 index 00000000..75622312 --- /dev/null +++ b/krita/plugins/viewplugins/separate_channels/kis_channel_separator.cc @@ -0,0 +1,301 @@ +/* + * This file is part of Krita + * + * 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; + + Q_UINT32 numberOfChannels = src->nChannels(); + KisColorSpace * srcCs = src->colorSpace(); + QValueVector channels = srcCs->channels(); + + // Use the flattened image, if required + switch(sourceOps) { + + case(ALL_LAYERS): + src = image->mergedImage(); + break; + default: + break; + } + + vKisPaintDeviceSP layers; + + QValueVector::const_iterator begin = channels.begin(); + QValueVector::const_iterator end = channels.end(); + + + QRect rect = src->exactBounds(); + + int i = 0; + Q_UINT32 channelIndex = 0; + for (QValueVector::const_iterator it = begin; it != end; ++it, ++channelIndex) + { + + KisChannelInfo * ch = (*it); + + if (ch->channelType() == KisChannelInfo::ALPHA && alphaOps != CREATE_ALPHA_SEPARATION) { + continue; + } + + Q_INT32 channelSize = ch->size(); + Q_INT32 channelPos = ch->pos(); + Q_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 (Q_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 (QValueVector::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 { + QStringList listMimeFilter = KoFilterManager::mimeFilter("application/x-krita", KoFilterManager::Export); + QString mimelist = listMimeFilter.join(" "); + + KFileDialog fd (QString::null, 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(); + QString mimefilter = fd.currentMimeFilter(); + + if (url.isEmpty()) + return; + + KisPaintLayerSP l = new KisPaintLayer( image, ch->name(), OPACITY_OPAQUE, *deviceIt); + QRect 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/krita/plugins/viewplugins/separate_channels/kis_channel_separator.h b/krita/plugins/viewplugins/separate_channels/kis_channel_separator.h new file mode 100644 index 00000000..0c0d80c9 --- /dev/null +++ b/krita/plugins/viewplugins/separate_channels/kis_channel_separator.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_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 + +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/krita/plugins/viewplugins/separate_channels/kis_separate_channels_plugin.cc b/krita/plugins/viewplugins/separate_channels/kis_separate_channels_plugin.cc new file mode 100644 index 00000000..4f7134f8 --- /dev/null +++ b/krita/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( kritaseparatechannels, KGenericFactory( "krita" ) ) + +KisSeparateChannelsPlugin::KisSeparateChannelsPlugin(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + + if ( parent->inherits("KisView") ) { + setInstance(KGenericFactory::instance()); + setXMLFile(locate("data","kritaplugins/imageseparate.rc"), true); + m_view = (KisView*) parent; + (void) new KAction(i18n("Separate Image..."), 0, 0, this, 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() == QDialog::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/krita/plugins/viewplugins/separate_channels/kis_separate_channels_plugin.h b/krita/plugins/viewplugins/separate_channels/kis_separate_channels_plugin.h new file mode 100644 index 00000000..a4a4fd61 --- /dev/null +++ b/krita/plugins/viewplugins/separate_channels/kis_separate_channels_plugin.h @@ -0,0 +1,45 @@ +/* + * This file is part of Krita + * + * 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 +public: + KisSeparateChannelsPlugin(QObject *parent, const char *name, const QStringList &); + virtual ~KisSeparateChannelsPlugin(); + +private slots: + + void slotSeparate(); + +private: + + KisView * m_view; +}; + +#endif diff --git a/krita/plugins/viewplugins/separate_channels/kritaseparatechannels.desktop b/krita/plugins/viewplugins/separate_channels/kritaseparatechannels.desktop new file mode 100644 index 00000000..63da737f --- /dev/null +++ b/krita/plugins/viewplugins/separate_channels/kritaseparatechannels.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=Krita/ViewPlugin +Type=Service +X-KDE-Library=kritaseparatechannels +X-Krita-Version=2 diff --git a/krita/plugins/viewplugins/separate_channels/wdg_separations.ui b/krita/plugins/viewplugins/separate_channels/wdg_separations.ui new file mode 100644 index 00000000..6c7a8cf7 --- /dev/null +++ b/krita/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/krita/plugins/viewplugins/shearimage/Makefile.am b/krita/plugins/viewplugins/shearimage/Makefile.am new file mode 100644 index 00000000..3c085d45 --- /dev/null +++ b/krita/plugins/viewplugins/shearimage/Makefile.am @@ -0,0 +1,24 @@ +kritarcdir = $(kde_datadir)/kritaplugins +kritarc_DATA = shearimage.rc + +EXTRA_DIST = $(kritarc_DATA) + + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = kritashearimage.la + +kde_services_DATA = kritashearimage.desktop + +kritashearimage_la_SOURCES = wdg_shearimage.ui shearimage.cc dlg_shearimage.cc +noinst_HEADERS = wdg_shearimage.h dlg_shearimage.h shearimage.h + +kritashearimage_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritashearimage_la_LIBADD = ../../../libkritacommon.la + +kritashearimage_la_METASOURCES = AUTO diff --git a/krita/plugins/viewplugins/shearimage/dlg_shearimage.cc b/krita/plugins/viewplugins/shearimage/dlg_shearimage.cc new file mode 100644 index 00000000..9a6a2f66 --- /dev/null +++ b/krita/plugins/viewplugins/shearimage/dlg_shearimage.cc @@ -0,0 +1,96 @@ +/* + * dlg_shearimage.cc - part of KimageShop^WKrayon^WKrita + * + * 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( QWidget * parent, + const char * name) + : super (parent, name, true, i18n("Shear Image"), Ok | Cancel, Ok) +{ + m_lock = false; + + m_page = new WdgShearImage(this, "shear_image"); + m_page->layout()->setMargin(0); + Q_CHECK_PTR(m_page); + + setMainWidget(m_page); + resize(m_page->sizeHint()); + + connect(this, SIGNAL(okClicked()), + this, SLOT(okClicked())); + +} + +DlgShearImage::~DlgShearImage() +{ + delete m_page; +} + +void DlgShearImage::setAngleX(Q_UINT32 angle) +{ + m_page->shearAngleX->setValue(angle); + m_oldAngle = angle; + +} + +void DlgShearImage::setAngleY(Q_UINT32 angle) +{ + m_page->shearAngleY->setValue(angle); + m_oldAngle = angle; + +} + +Q_INT32 DlgShearImage::angleX() +{ + return (Q_INT32)qRound(m_page->shearAngleX->value()); +} + +Q_INT32 DlgShearImage::angleY() +{ + return (Q_INT32)qRound(m_page->shearAngleY->value()); +} + +// SLOTS + +void DlgShearImage::okClicked() +{ + accept(); +} + +#include "dlg_shearimage.moc" diff --git a/krita/plugins/viewplugins/shearimage/dlg_shearimage.h b/krita/plugins/viewplugins/shearimage/dlg_shearimage.h new file mode 100644 index 00000000..183f166a --- /dev/null +++ b/krita/plugins/viewplugins/shearimage/dlg_shearimage.h @@ -0,0 +1,54 @@ +/* + * dlg_shearimage.h -- part of KimageShop^WKrayon^WKrita + * + * 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 + +public: + + DlgShearImage(QWidget * parent = 0, + const char* name = 0); + ~DlgShearImage(); + + void setAngleX(Q_UINT32 w); + void setAngleY(Q_UINT32 w); + Q_INT32 angleX(); + Q_INT32 angleY(); + +private slots: + + void okClicked(); + +private: + + WdgShearImage * m_page; + double m_oldAngle; + bool m_lock; + +}; + +#endif // DLG_SHEARIMAGE diff --git a/krita/plugins/viewplugins/shearimage/kritashearimage.desktop b/krita/plugins/viewplugins/shearimage/kritashearimage.desktop new file mode 100644 index 00000000..1b1e8ad0 --- /dev/null +++ b/krita/plugins/viewplugins/shearimage/kritashearimage.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=Krita/ViewPlugin +Type=Service +X-KDE-Library=kritashearimage +X-Krita-Version=2 diff --git a/krita/plugins/viewplugins/shearimage/shearimage.cc b/krita/plugins/viewplugins/shearimage/shearimage.cc new file mode 100644 index 00000000..d8c839ce --- /dev/null +++ b/krita/plugins/viewplugins/shearimage/shearimage.cc @@ -0,0 +1,113 @@ +/* + * shearimage.cc -- Part of Krita + * + * 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( kritashearimage, ShearImageFactory( "krita" ) ) + +// XXX: this plugin could also provide layer scaling/resizing +ShearImage::ShearImage(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + if ( parent->inherits("KisView") ) + { + setInstance(ShearImageFactory::instance()); + setXMLFile(locate("data","kritaplugins/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; + } +} + +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() == QDialog::Accepted) { + Q_INT32 angleX = dlgShearImage->angleX(); + Q_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() == QDialog::Accepted) { + Q_INT32 angleX = dlgShearImage->angleX(); + Q_INT32 angleY = dlgShearImage->angleY(); + m_view->shearLayer(angleX, angleY); + + } + delete dlgShearImage; +} + +#include "shearimage.moc" diff --git a/krita/plugins/viewplugins/shearimage/shearimage.h b/krita/plugins/viewplugins/shearimage/shearimage.h new file mode 100644 index 00000000..bfff2ac2 --- /dev/null +++ b/krita/plugins/viewplugins/shearimage/shearimage.h @@ -0,0 +1,46 @@ +/* + * shearimage.h -- Part of Krita + * + * 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 +public: + ShearImage(QObject *parent, const char *name, const QStringList &); + virtual ~ShearImage(); + +private slots: + + void slotShearImage(); + void slotShearLayer(); + +private: + + KisView * m_view; + KisPainter * m_painter; + +}; + +#endif // SHEARIMAGE_H diff --git a/krita/plugins/viewplugins/shearimage/shearimage.rc b/krita/plugins/viewplugins/shearimage/shearimage.rc new file mode 100644 index 00000000..c13e341f --- /dev/null +++ b/krita/plugins/viewplugins/shearimage/shearimage.rc @@ -0,0 +1,13 @@ + + + + &Image + + + + La&yer + + + + + diff --git a/krita/plugins/viewplugins/shearimage/wdg_shearimage.ui b/krita/plugins/viewplugins/shearimage/wdg_shearimage.ui new file mode 100644 index 00000000..20de0b6b --- /dev/null +++ b/krita/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/krita/plugins/viewplugins/substrate/Makefile.am b/krita/plugins/viewplugins/substrate/Makefile.am new file mode 100644 index 00000000..5f86ea99 --- /dev/null +++ b/krita/plugins/viewplugins/substrate/Makefile.am @@ -0,0 +1,25 @@ +kritarcdir = $(kde_datadir)/kritaplugins +kritarc_DATA = substrate.rc + +EXTRA_DIST = $(kritarc_DATA) + + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = kritasubstrate.la + +kritasubstrate_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 + +kritasubstrate_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritasubstrate_la_LIBADD = ../../../libkritacommon.la + +kde_services_DATA = kritasubstrate.desktop + +METASOURCES = AUTO diff --git a/krita/plugins/viewplugins/substrate/dlg_substrate.cc b/krita/plugins/viewplugins/substrate/dlg_substrate.cc new file mode 100644 index 00000000..d1bbe38f --- /dev/null +++ b/krita/plugins/viewplugins/substrate/dlg_substrate.cc @@ -0,0 +1,59 @@ +/* + * dlg_substrate.cc - part of KimageShop^WKrayon^WKrita + * + * 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( QWidget * parent, + const char * name) + : super (parent, name, true, i18n("Color Range"), Ok | Cancel, Ok) +{ + m_previewPix = QPixmap(); + m_page = new WdgSubstrate(this, "substrate"); + Q_CHECK_PTR(m_page); + setCaption(i18n("Substrate")); + setMainWidget(m_page); + resize(m_page -> size()); + + connect(this, SIGNAL(okClicked()), + this, SLOT(okClicked())); +} + +DlgSubstrate::~DlgSubstrate() +{ + delete m_page; +} + +void DlgSubstrate::setPixmap(QPixmap pix) +{ + m_previewPix = pix; + m_previewPix.detach(); +} + +void DlgSubstrate::okClicked() +{ + accept(); +} + +#include "dlg_substrate.moc" + diff --git a/krita/plugins/viewplugins/substrate/dlg_substrate.h b/krita/plugins/viewplugins/substrate/dlg_substrate.h new file mode 100644 index 00000000..0a566b11 --- /dev/null +++ b/krita/plugins/viewplugins/substrate/dlg_substrate.h @@ -0,0 +1,61 @@ +/* + * dlg_substrate.h -- part of KimageShop^WKrayon^WKrita + * + * 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 + +public: + + DlgSubstrate(QWidget * parent = 0, + const char* name = 0); + ~DlgSubstrate(); + + /** + * Set the initial preview pixmap + */ + void setPixmap(QPixmap pix); + +private slots: + + void okClicked(); + +private: + + WdgSubstrate * m_page; + QPixmap m_previewPix; +}; + +#endif // DLG_SUBSTRATE diff --git a/krita/plugins/viewplugins/substrate/kis_repeating_substrate.cc b/krita/plugins/viewplugins/substrate/kis_repeating_substrate.cc new file mode 100644 index 00000000..e69de29b diff --git a/krita/plugins/viewplugins/substrate/kis_repeating_substrate.h b/krita/plugins/viewplugins/substrate/kis_repeating_substrate.h new file mode 100644 index 00000000..9dc512d1 --- /dev/null +++ b/krita/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 QRect & /*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/krita/plugins/viewplugins/substrate/kritasubstrate.desktop b/krita/plugins/viewplugins/substrate/kritasubstrate.desktop new file mode 100644 index 00000000..85e58263 --- /dev/null +++ b/krita/plugins/viewplugins/substrate/kritasubstrate.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=Krita/ViewPlugin +Type=Service +X-KDE-Library=kritasubstrate +X-Krita-Version=2 diff --git a/krita/plugins/viewplugins/substrate/substrate.cc b/krita/plugins/viewplugins/substrate/substrate.cc new file mode 100644 index 00000000..aac9ef94 --- /dev/null +++ b/krita/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( kritasubstrate, SubstrateFactory( "krita" ) ) + +SubstratePlugin::SubstratePlugin(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + + if ( parent->inherits("KisView") ) + { + setInstance(SubstrateFactory::instance()); + setXMLFile(locate("data","kritaplugins/substrate.rc"), true); + + (void) new KAction(i18n("&Substrate..."), 0, 0, this, SLOT(slotSubstrateActivated()), actionCollection(), "substrate"); + + m_view = (KisView*) parent; + } +} + +SubstratePlugin::~SubstratePlugin() +{ +} + +void SubstratePlugin::slotSubstrateActivated() +{ + DlgSubstrate * dlgSubstrate = new DlgSubstrate(m_view, "Substrate"); + Q_CHECK_PTR(dlgSubstrate); + if (dlgSubstrate -> exec() == QDialog::Accepted) { + // Retrieve changes made by dialog + // Apply changes to layer (selection) + } + delete dlgSubstrate; +} + +#include "substrate.moc" + diff --git a/krita/plugins/viewplugins/substrate/substrate.h b/krita/plugins/viewplugins/substrate/substrate.h new file mode 100644 index 00000000..ebb9e48e --- /dev/null +++ b/krita/plugins/viewplugins/substrate/substrate.h @@ -0,0 +1,44 @@ +/* + * substrate.h -- Part of Krita + * + * 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 +public: + SubstratePlugin(QObject *parent, const char *name, const QStringList &); + virtual ~SubstratePlugin(); + +private slots: + void slotSubstrateActivated(); + +private: + KisView * m_view; + KisPainter * m_painter; + +}; + +#endif // SUBSTATE_H diff --git a/krita/plugins/viewplugins/substrate/substrate.rc b/krita/plugins/viewplugins/substrate/substrate.rc new file mode 100644 index 00000000..4251e87f --- /dev/null +++ b/krita/plugins/viewplugins/substrate/substrate.rc @@ -0,0 +1,8 @@ + + + + Image + + + + diff --git a/krita/plugins/viewplugins/substrate/wdgsubstrate.ui b/krita/plugins/viewplugins/substrate/wdgsubstrate.ui new file mode 100644 index 00000000..846b43a7 --- /dev/null +++ b/krita/plugins/viewplugins/substrate/wdgsubstrate.ui @@ -0,0 +1,221 @@ + +WdgSubstrate + + + Form1 + + + + 0 + 0 + 478 + 358 + + + + + unnamed + + + + grpCustom + + + Custom Canvas Definition + + + + unnamed + + + + layout3 + + + + unnamed + + + + + Custom + + + + cmbPredefinedCanvases + + + + + bnBackground + + + + + + + + textLabel1 + + + Save custom substrate as: + + + + + lblPredefined + + + &Pre-defined canvas types: + + + cmbPredefinedCanvases + + + + + lblColor + + + &Basic color: + + + bnBackground + + + + + lineEdit1 + + + + + + + layout2 + + + + 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/krita/plugins/viewplugins/variations/Makefile.am b/krita/plugins/viewplugins/variations/Makefile.am new file mode 100644 index 00000000..d4908aa6 --- /dev/null +++ b/krita/plugins/viewplugins/variations/Makefile.am @@ -0,0 +1,25 @@ +kritarcdir = $(kde_datadir)/kritaplugins +kritarc_DATA = variations.rc + +EXTRA_DIST = $(kritarc_DATA) + + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = kritavariations.la + +kritavariations_la_SOURCES = variations.cc dlg_variations.cc wdg_variations.ui +noinst_HEADERS = wdg_variations.h + +kritavariations_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritavariations_la_LIBADD = ../../../libkritacommon.la + +kde_services_DATA = kritavariations.desktop + +kritavariations_la_METASOURCES = AUTO diff --git a/krita/plugins/viewplugins/variations/dlg_variations.cc b/krita/plugins/viewplugins/variations/dlg_variations.cc new file mode 100644 index 00000000..7d81b078 --- /dev/null +++ b/krita/plugins/viewplugins/variations/dlg_variations.cc @@ -0,0 +1,58 @@ +/* + * dlg_variations.cc - part of KimageShop^WKrayon^WKrita + * + * 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( QWidget * parent, + const char * name) + : super (parent, name, true, i18n("Color Range"), Ok | Cancel, Ok) +{ + m_previewPix = QPixmap(); + m_page = new WdgVariations(this, "variations"); + Q_CHECK_PTR(m_page); + setCaption(i18n("Variations")); + setMainWidget(m_page); + resize(m_page -> size()); + + connect(this, SIGNAL(okClicked()), + this, SLOT(okClicked())); +} + +DlgVariations::~DlgVariations() +{ + delete m_page; +} + +void DlgVariations::setPixmap(QPixmap pix) +{ + m_previewPix = pix; + m_previewPix.detach(); +} + +void DlgVariations::okClicked() +{ + accept(); +} + +#include "dlg_variations.moc" diff --git a/krita/plugins/viewplugins/variations/dlg_variations.h b/krita/plugins/viewplugins/variations/dlg_variations.h new file mode 100644 index 00000000..48538687 --- /dev/null +++ b/krita/plugins/viewplugins/variations/dlg_variations.h @@ -0,0 +1,61 @@ +/* + * dlg_variations.h -- part of KimageShop^WKrayon^WKrita + * + * 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 + +public: + + DlgVariations(QWidget * parent = 0, + const char* name = 0); + ~DlgVariations(); + + /** + * Set the initial preview pixmap + */ + void setPixmap(QPixmap pix); + +private slots: + + void okClicked(); + +private: + + WdgVariations * m_page; + QPixmap m_previewPix; +}; + +#endif // DLG_VARIATIONS diff --git a/krita/plugins/viewplugins/variations/kritavariations.desktop b/krita/plugins/viewplugins/variations/kritavariations.desktop new file mode 100644 index 00000000..f0e06659 --- /dev/null +++ b/krita/plugins/viewplugins/variations/kritavariations.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=Krita/ViewPlugin +Type=Service +X-KDE-Library=kritavariations +X-Krita-Version=2 diff --git a/krita/plugins/viewplugins/variations/variations.cc b/krita/plugins/viewplugins/variations/variations.cc new file mode 100644 index 00000000..eef4d6e5 --- /dev/null +++ b/krita/plugins/viewplugins/variations/variations.cc @@ -0,0 +1,88 @@ +/* + * variation.h -- Part of Krita + * + * 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( kritavariations, VariationsFactory( "krita" ) ) + +Variations::Variations(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + + if ( parent->inherits("KisView") ) + { + setInstance(VariationsFactory::instance()); + setXMLFile(locate("data","kritaplugins/variations.rc"), true); + + (void) new KAction(i18n("&Variations..."), 0, 0, this, SLOT(slotVariationsActivated()), actionCollection(), "variations"); + + m_view = (KisView*) parent; + } +} + +Variations::~Variations() +{ +} + +void Variations::slotVariationsActivated() +{ + DlgVariations * dlgVariations = new DlgVariations(m_view, "Variations"); + Q_CHECK_PTR(dlgVariations); + // Render layer to a QIMage -- keep in mind possibility of selection + + // Scale QImage + + // Set original QImage in dialog + + if (dlgVariations -> exec() == QDialog::Accepted) { + // Retrieve changes made by dialog + // Apply changes to layer (selection) + } + delete dlgVariations; +} + +#include "variations.moc" + diff --git a/krita/plugins/viewplugins/variations/variations.h b/krita/plugins/viewplugins/variations/variations.h new file mode 100644 index 00000000..7aa40daf --- /dev/null +++ b/krita/plugins/viewplugins/variations/variations.h @@ -0,0 +1,44 @@ +/* + * variation.h -- Part of Krita + * + * 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 +public: + Variations(QObject *parent, const char *name, const QStringList &); + virtual ~Variations(); + +private slots: + void slotVariationsActivated(); + +private: + KisView * m_view; + KisPainter * m_painter; + +}; + +#endif // VARIATIONS_H diff --git a/krita/plugins/viewplugins/variations/variations.rc b/krita/plugins/viewplugins/variations/variations.rc new file mode 100644 index 00000000..9a3ac985 --- /dev/null +++ b/krita/plugins/viewplugins/variations/variations.rc @@ -0,0 +1,8 @@ + + + + Image + + + + diff --git a/krita/plugins/viewplugins/variations/wdg_variations.ui b/krita/plugins/viewplugins/variations/wdg_variations.ui new file mode 100644 index 00000000..e6d8336d --- /dev/null +++ b/krita/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 + + + + + + + layout5 + + + + 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/krita/sdk/Makefile.am b/krita/sdk/Makefile.am new file mode 100644 index 00000000..e6f4f4a5 --- /dev/null +++ b/krita/sdk/Makefile.am @@ -0,0 +1,23 @@ +KDE_OPTIONS = nofinal + +INCLUDES = $(KOFFICE_INCLUDES) $(KOPAINTER_INCLUDES) \ + $(all_includes) + +noinst_LTLIBRARIES = libkritasdk.la +libkritasdk_la_SOURCES = kis_progress_subject.cc +libkritasdk_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/krita/sdk/kis_annotation.h b/krita/sdk/kis_annotation.h new file mode 100644 index 00000000..03287004 --- /dev/null +++ b/krita/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 Krita. + * + * An annotation can be of something like a QByteArray or a QString 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 krita 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 QString & type, const QString & description, const QByteArray & data) + : m_type(type), + m_description(description), + m_annotation(data) {}; + + /** + * @return a non-localized string identifiying the type of the annotation + */ + QString & type() {return m_type;}; + + /** + * @return a localized string describing the type of the annotations + * for user interface purposes. + */ + QString & description() {return m_description;}; + + /** + * @return a binary blob representation of this annotation + */ + QByteArray & annotation() { return m_annotation;}; + +private: + + QString m_type; + QString m_description; + QByteArray 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/krita/sdk/kis_canvas_controller.h b/krita/sdk/kis_canvas_controller.h new file mode 100644 index 00000000..99d43c38 --- /dev/null +++ b/krita/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 QWidget; +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 Q_INT32 horzValue() const = 0; + + /** + * @return the value of the vertical scrollbar + */ + virtual Q_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(Q_INT32 x, Q_INT32 y) = 0; + + /** + * Tell all of the canvas to repaint itself. + */ + virtual void updateCanvas() = 0; + + + /** + * Tell the canvas to repaint the rectangle defined by x, y, w and h. + * The coordinates are image coordinates. + */ + virtual void updateCanvas(Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h) = 0; + + /** + * Tell the canvas repaint the specified rectangle. The coordinates + * are image coordinates, not view coordinates. + */ + virtual void updateCanvas(const QRect& 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(Q_INT32 x, Q_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(Q_INT32 x, Q_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(Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_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 QRect& 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(QRect(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 QPoint viewToWindow(const QPoint& pt) = 0; + virtual KisPoint viewToWindow(const KisPoint& pt) = 0; + virtual QRect viewToWindow(const QRect& rc) = 0; + virtual KisRect viewToWindow(const KisRect& rc) = 0; + virtual void viewToWindow(Q_INT32 *x, Q_INT32 *y) = 0; + + /** + * Conversion functions from image coordinates to view coordinates + */ + virtual QPoint windowToView(const QPoint& pt) = 0; + virtual KisPoint windowToView(const KisPoint& pt) = 0; + virtual QRect windowToView(const QRect& rc) = 0; + virtual KisRect windowToView(const KisRect& rc) = 0; + virtual void windowToView(Q_INT32 *x, Q_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 QCursor setCanvasCursor(const QCursor & 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/krita/sdk/kis_canvas_observer.h b/krita/sdk/kis_canvas_observer.h new file mode 100644 index 00000000..e62d23f3 --- /dev/null +++ b/krita/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/krita/sdk/kis_canvas_subject.h b/krita/sdk/kis_canvas_subject.h new file mode 100644 index 00000000..7fcef988 --- /dev/null +++ b/krita/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 QWidget; +class QCursor; +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/krita/sdk/kis_debug_areas.h b/krita/sdk/kis_debug_areas.h new file mode 100644 index 00000000..67cb3566 --- /dev/null +++ b/krita/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/krita/sdk/kis_generic_registry.h b/krita/sdk/kis_generic_registry.h new file mode 100644 index 00000000..bb930d90 --- /dev/null +++ b/krita/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 Krita. Krita 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 QString& 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 QString& 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 QString& 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 QString& 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/krita/sdk/kis_global.h b/krita/sdk/kis_global.h new file mode 100644 index 00000000..31a982da --- /dev/null +++ b/krita/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 Q_UINT8 Q_UINT8_MAX = UCHAR_MAX; +const Q_UINT16 Q_UINT16_MAX = 65535; + +const Q_INT32 Q_INT32_MAX = (2147483647); +const Q_INT32 Q_INT32_MIN = (-2147483647-1); + +const Q_UINT8 OPACITY_TRANSPARENT = 0; +const Q_UINT8 OPACITY_OPAQUE = UCHAR_MAX; + +const Q_UINT8 MAX_SELECTED = UCHAR_MAX; +const Q_UINT8 MIN_SELECTED = 0; +const Q_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; Qt only supports 256, and even + * this is downscaled to 127 levels because the line would be too jittery, and + * the amount of masks take too much memory otherwise. + */ +const Q_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 krita { + + // String constants for palettes and palette widgets + const QString TOOL_OPTION_WIDGET ("tooloptions"); + + const QString CONTROL_PALETTE ("controlpalette"); + const QString PAINTBOX ("paintbox"); + const QString COLORBOX ("colorbox"); + const QString LAYERBOX ("layerbox"); +} + +#endif // KISGLOBAL_H_ + diff --git a/krita/sdk/kis_id.h b/krita/sdk/kis_id.h new file mode 100644 index 00000000..b5651505 --- /dev/null +++ b/krita/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 + +/** + * Krita 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(QString::null), m_name(QString::null) {} + + KisID(const QString & id, const QString & name = QString::null) + : m_id(id), + m_name(name) {}; + + QString id() const { return m_id; }; + QString 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: + + QString m_id; + QString 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 QValueList KisIDList; + +#endif // _KIS_ID_H_ diff --git a/krita/sdk/kis_integer_maths.h b/krita/sdk/kis_integer_maths.h new file mode 100644 index 00000000..c8db9aee --- /dev/null +++ b/krita/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/krita/sdk/kis_progress_display_interface.h b/krita/sdk/kis_progress_display_interface.h new file mode 100644 index 00000000..bf0dede3 --- /dev/null +++ b/krita/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 = QEvent::User + 42 + 42; + + class UpdateEvent : QCustomEvent { + + public: + + UpdateEvent(int percent) : QCustomEvent(ProgressEventBase + 1), m_percent(percent) {}; + int m_percent; + }; + + class UpdateStageEvent : QCustomEvent { + + public: + + UpdateStageEvent(const QString & stage, int percent) : QCustomEvent(ProgressEventBase + 2 ), m_stage(stage), m_percent(percent) {}; + QString m_stage; + int m_percent; + }; + + class DoneEvent : QCustomEvent { + DoneEvent() : QCustomEvent(ProgressEventBase + 3){}; + }; + + class ErrorEvent : QCustomEvent { + ErrorEvent() : QCustomEvent(ProgressEventBase + 4){}; + }; + + class DestroyedEvent: QCustomEvent { + DestroyedEvent() : QCustomEvent(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/krita/sdk/kis_progress_subject.cc b/krita/sdk/kis_progress_subject.cc new file mode 100644 index 00000000..fa53086b --- /dev/null +++ b/krita/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/krita/sdk/kis_progress_subject.h b/krita/sdk/kis_progress_subject.h new file mode 100644 index 00000000..d936c7b7 --- /dev/null +++ b/krita/sdk/kis_progress_subject.h @@ -0,0 +1,44 @@ +/* + * 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 QObject { + Q_OBJECT + +protected: + KisProgressSubject() {}; + KisProgressSubject(QObject * parent, const char * name) : QObject(parent, name) {}; + virtual ~KisProgressSubject(); + +public: + virtual void cancel() = 0; + +signals: + void notifyProgress(int percent); + void notifyProgressStage(const QString& stage, int percent); + void notifyProgressDone(); + void notifyProgressError(); +}; + +#endif // KIS_PROGRESS_SUBJECT_H_ + diff --git a/krita/sdk/kis_shared_ptr_vector.h b/krita/sdk/kis_shared_ptr_vector.h new file mode 100644 index 00000000..0a7695a1 --- /dev/null +++ b/krita/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 + +/** + * QValueVector 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 QValueVector< KSharedPtr > +{ + typedef QValueVector< 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) + { + qFill(first, last, 0); + return super::erase(first, last); + } + + bool contains(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/krita/sdk/kis_undo_adapter.h b/krita/sdk/kis_undo_adapter.h new file mode 100644 index 00000000..32cd655a --- /dev/null +++ b/krita/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 QString; +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 QString& macroName) = 0; + virtual void endMacro() = 0; + +private: + KisUndoAdapter(const KisUndoAdapter&); + KisUndoAdapter& operator=(const KisUndoAdapter&); +}; + + +#endif // KIS_UNDO_ADAPTER_H_ + diff --git a/krita/todo-1.6 b/krita/todo-1.6 new file mode 100644 index 00000000..d38c62ea --- /dev/null +++ b/krita/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. Krita'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 -> Krita + 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/krita/ui/Makefile.am b/krita/ui/Makefile.am new file mode 100644 index 00000000..638ae634 --- /dev/null +++ b/krita/ui/Makefile.am @@ -0,0 +1,75 @@ +INCLUDES = \ + -I$(srcdir) \ + -I$(srcdir)/../sdk \ + -I$(srcdir)/../core \ + -I$(srcdir)/../kritacolor \ + $(KOFFICE_INCLUDES) \ + $(KOPAINTER_INCLUDES) \ + $(KDE_INCLUDES) \ + $(all_includes) + +lib_LTLIBRARIES = libkritaui.la +libkritaui_la_LDFLAGS = -version-info 1:0:0 -no-undefined $(all_libraries) +libkritaui_la_LIBADD = ../sdk/libkritasdk.la ../core/libkritaimage.la ../kritacolor/libkritacolor.la \ + $(LCMS_LIBS) $(LIB_KOFFICEUI) $(LIB_KOPAINTER) $(LIB_KOPALETTE) $(LIB_XINPUTEXT) $(GLLIB) + +libkritaui_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/krita/ui/imageviewer.cc b/krita/ui/imageviewer.cc new file mode 100644 index 00000000..490f3451 --- /dev/null +++ b/krita/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(QWidget *widget, const char * name) + : QScrollView(widget, name) + , m_isDragging(false) + , m_image(QPixmap()) +{ + m_label = new QLabel( viewport()); + setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + setCursor(KisCursor::handCursor()); + addChild(m_label); +} + +void ImageViewer::setImage(QImage & image) +{ + m_image = QPixmap(image); + m_label->setPixmap(m_image); + resizeContents( m_image.width(), m_image.height() ); + repaintContents(false); +} + +void ImageViewer::contentsMousePressEvent(QMouseEvent *event) +{ + if(LeftButton == event->button()) { + setCursor(KisCursor::closedHandCursor()); + m_currentPos = event->globalPos(); + m_isDragging = true; + } +} + +void ImageViewer::contentsMouseReleaseEvent(QMouseEvent *event) +{ + if(LeftButton == event->button()) { + setCursor(KisCursor::handCursor()); + m_currentPos = event->globalPos(); + m_isDragging = false; + } +} + +void ImageViewer::contentsMouseMoveEvent(QMouseEvent *event) +{ + if(m_isDragging) { + QPoint delta = m_currentPos - event->globalPos(); + scrollBy(delta.x(), delta.y()); + m_currentPos = event->globalPos(); + } +} + +#include "imageviewer.moc" diff --git a/krita/ui/imageviewer.h b/krita/ui/imageviewer.h new file mode 100644 index 00000000..17b482c6 --- /dev/null +++ b/krita/ui/imageviewer.h @@ -0,0 +1,52 @@ +/*************************************************************************** + * 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 QLabel; + +/** + * 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 QScrollView { + Q_OBJECT + +public: + ImageViewer(QWidget *widget, const char * name = 0); + + void setImage(QImage & image); + + void contentsMousePressEvent(QMouseEvent *event); + void contentsMouseReleaseEvent(QMouseEvent *event); + void contentsMouseMoveEvent(QMouseEvent *event); + void wheelEvent(QWheelEvent * event) { event->ignore(); }; +private: + QLabel* m_label; + bool m_isDragging; + QPoint m_currentPos; + QPixmap m_image; +}; + +#endif diff --git a/krita/ui/kcurve.cc b/krita/ui/kcurve.cc new file mode 100644 index 00000000..8e50804f --- /dev/null +++ b/krita/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 + +// Qt includes. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// KDE includes. + +#include +#include +#include + +// Local includes. + +#include "kcurve.h" + +KCurve::KCurve(QWidget *parent, const char *name, WFlags f) + : QWidget(parent, name, f) +{ + m_grab_point = NULL; + m_readOnlyMode = false; + m_guideVisible = false; + m_dragging = false; + m_pix = NULL; + + setMouseTracking(true); + setPaletteBackgroundColor(Qt::NoBackground); + setMinimumSize(150, 50); + QPair *p = new QPair; + p->first = 0.0; p->second=0.0; + m_points.append(p); + p = new QPair; + p->first = 1.0; p->second=1.0; + m_points.append(p); + m_points.setAutoDelete(true); + setFocusPolicy(QWidget::StrongFocus); +} + +KCurve::~KCurve() +{ + if (m_pix) delete m_pix; +} + +void KCurve::reset(void) +{ + m_grab_point = NULL; + m_guideVisible = false; + repaint(false); +} + +void KCurve::setCurveGuide(QColor color) +{ + m_guideVisible = true; + m_colorGuide = color; + repaint(false); +} + +void KCurve::setPixmap(QPixmap pix) +{ + if (m_pix) delete m_pix; + m_pix = new QPixmap(pix); + repaint(false); +} + +void KCurve::keyPressEvent(QKeyEvent *e) +{ + if(e->key() == Qt::Key_Delete || e->key() == Qt::Key_Backspace) + { + QPair *closest_point=NULL; + if(m_grab_point) + { + //first find closest point to get focus afterwards + QPair *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; + repaint(false); + } + else + QWidget::keyPressEvent(e); +} + +void KCurve::paintEvent(QPaintEvent *) +{ + int x, y; + int wWidth = width(); + int wHeight = height(); + + x = 0; + y = 0; + + // Drawing selection or all histogram values. + // A QPixmap is used for enable the double buffering. + + QPixmap pm(size()); + QPainter p1; + p1.begin(&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(QPen::QPen(Qt::gray, 1, Qt::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(QPen::QPen(Qt::black, 1, Qt::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 ) + { + QPair *p = m_points.first(); + + while(p) + { + double curveX = p->first; + double curveY = p->second; + + if(p == m_grab_point) + { + p1.setPen(QPen::QPen(Qt::red, 3, Qt::SolidLine)); + p1.drawEllipse( int(curveX * wWidth) - 2, + wHeight - 2 - int(curveY * wHeight), 4, 4 ); + } + else + { + p1.setPen(QPen::QPen(Qt::red, 1, Qt::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 ( QMouseEvent * e ) +{ + if (m_readOnlyMode) return; + + QPair *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 + + QPair *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 QPair; + closest_point->first = x; + closest_point->second = y; + m_points.append(closest_point); + } + else if(distance * width() > 5) + { + closest_point = new QPair; + 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(); + } + repaint(false); +} + +void KCurve::mouseReleaseEvent ( QMouseEvent * e ) +{ + if (m_readOnlyMode) return; + + if (e->button() != Qt::LeftButton) + return; + + setCursor( KCursor::arrowCursor() ); + m_dragging = false; + repaint(false); + emit modified(); +} + +void KCurve::mouseMoveEvent ( QMouseEvent * 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 shape if on top + { + double distance = 1000; + double ydistance = 1000; + QPair *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(); + } + + repaint(false); +} + +double KCurve::getCurveValue(double x) +{ + return getCurveValue(m_points, x); +} + +double KCurve::getCurveValue(QPtrList > &curve, double x) +{ + double t; + QPair *p; + QPair *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; +} + +QPtrList > KCurve::getCurve() +{ + QPtrList > outlist; + QPair *p; + QPair *outpoint; + + p = m_points.first(); + while(p) + { + outpoint = new QPair(p->first, p->second); + outlist.append(outpoint); + p = m_points.next(); + } + return outlist; +} + +void KCurve::setCurve(QPtrList >inlist) +{ + QPair *p; + QPair *inpoint; + + m_points.clear(); + + inpoint = inlist.first(); + while(inpoint) + { + p = new QPair(inpoint->first, inpoint->second); + m_points.append(p); + inpoint = inlist.next(); + } +} + +void KCurve::leaveEvent( QEvent * ) +{ +} + +#include "kcurve.moc" diff --git a/krita/ui/kcurve.h b/krita/ui/kcurve.h new file mode 100644 index 00000000..412efe5b --- /dev/null +++ b/krita/ui/kcurve.h @@ -0,0 +1,79 @@ +/* ============================================================ + * + * 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 + +// Qt includes. + +#include +#include +#include +#include +#include +class KRITAUI_EXPORT KCurve : public QWidget +{ +Q_OBJECT + +public: + KCurve(QWidget *parent = 0, const char *name = 0, WFlags f = 0); + + virtual ~KCurve(); + + void reset(void); + void setCurveGuide(QColor color); + void setPixmap(QPixmap pix); + + +signals: + + void modified(void); + +protected: + + void keyPressEvent(QKeyEvent *); + void paintEvent(QPaintEvent *); + void mousePressEvent (QMouseEvent * e); + void mouseReleaseEvent ( QMouseEvent * e ); + void mouseMoveEvent ( QMouseEvent * e ); + void leaveEvent ( QEvent * ); + +public: + static double getCurveValue(QPtrList > &curve, double x); + double getCurveValue(double x); + + QPtrList > getCurve(); + void setCurve(QPtrList >inlist); + +private: + double m_leftmost; + double m_rightmost; + QPair *m_grab_point; + bool m_dragging; + double m_grabOffsetX; + double m_grabOffsetY; + + bool m_readOnlyMode; + bool m_guideVisible; + QColor m_colorGuide; + QPtrList > m_points; + QPixmap *m_pix; +}; + + +#endif /* KCURVE_H */ diff --git a/krita/ui/kis_aboutdata.h b/krita/ui/kis_aboutdata.h new file mode 100644 index 00000000..385cb4b2 --- /dev/null +++ b/krita/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 * newKritaAboutData() +{ + KAboutData * aboutData = new KAboutData( "krita", + I18N_NOOP("Krita"), + KOFFICE_VERSION_STRING, + I18N_NOOP("KOffice image manipulation application"), + KAboutData::License_GPL, + I18N_NOOP("(c) 1999-2006 The Krita team.\n"), + "", + "http://www.koffice.org/krita", + "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/krita/ui/kis_autobrush.cc b/krita/ui/kis_autobrush.cc new file mode 100644 index 00000000..d1f6dce2 --- /dev/null +++ b/krita/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(QWidget *parent, const char* name, const QString& caption) : KisWdgAutobrush(parent, name) +{ + setCaption(caption); + + m_linkSize = true; + m_linkFade = true; + + linkFadeToggled(m_linkSize); + linkSizeToggled(m_linkFade); + + connect(bnLinkSize, SIGNAL(toggled(bool)), this, SLOT(linkSizeToggled( bool ))); + connect(bnLinkFade, SIGNAL(toggled(bool)), this, SLOT(linkFadeToggled( bool ))); + + connect((QObject*)comboBoxShape, SIGNAL(activated(int)), this, SLOT(paramChanged())); + spinBoxWidth->setMinValue(1); + connect(spinBoxWidth,SIGNAL(valueChanged(int)),this,SLOT(spinBoxWidthChanged(int))); + spinBoxHeigth->setMinValue(1); + connect(spinBoxHeigth,SIGNAL(valueChanged(int)),this,SLOT(spinBoxHeigthChanged(int))); + spinBoxHorizontal->setMinValue(0); + connect(spinBoxHorizontal,SIGNAL(valueChanged(int)),this,SLOT(spinBoxHorizontalChanged(int))); + spinBoxVertical->setMinValue(0); + connect(spinBoxVertical,SIGNAL(valueChanged(int)),this,SLOT(spinBoxVerticalChanged(int))); + + m_brsh = new QImage(1,1,32); + Q_CHECK_PTR(m_brsh); + + paramChanged(); + + + connect(brushPreview, SIGNAL(clicked()), SLOT(paramChanged())); + +} + +void KisAutobrush::resizeEvent ( QResizeEvent * ) +{ + brushPreview->setMinimumHeight(brushPreview->width()); // dirty hack ! + brushPreview->setMaximumHeight(brushPreview->width()); // dirty hack ! +} + +void KisAutobrush::activate() +{ + paramChanged(); +} + +void KisAutobrush::paramChanged() +{ + Q_INT32 fh = QMIN( spinBoxWidth->value()/2, spinBoxHorizontal->value() ) ; + Q_INT32 fv = QMIN( 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); + + QPixmap p; + QImage 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/krita/ui/kis_autobrush.h b/krita/ui/kis_autobrush.h new file mode 100644 index 00000000..35392320 --- /dev/null +++ b/krita/ui/kis_autobrush.h @@ -0,0 +1,55 @@ +/* + * 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 +public: + KisAutobrush(QWidget *parent, const char* name, const QString& 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 ( QResizeEvent * ); + +private: + QImage* m_brsh; + bool m_linkSize; + bool m_linkFade; +}; + + +#endif diff --git a/krita/ui/kis_autogradient.cc b/krita/ui/kis_autogradient.cc new file mode 100644 index 00000000..79b6bb63 --- /dev/null +++ b/krita/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(QWidget *parent, const char* name, const QString& caption) : KisWdgAutogradient(parent, name) +{ + setCaption(caption); + m_autogradientResource = new KisAutogradientResource(); + m_autogradientResource->createSegment( INTERP_LINEAR, COLOR_INTERP_RGB, 0.0, 1.0, 0.5, Qt::black, Qt::white ); + connect(gradientSlider, SIGNAL( sigSelectedSegment( KisGradientSegment* ) ), SLOT( slotSelectedSegment(KisGradientSegment*) )); + connect(gradientSlider, SIGNAL( sigChangedSegment(KisGradientSegment*) ), SLOT( slotChangedSegment(KisGradientSegment*) )); + gradientSlider->setGradientResource( m_autogradientResource ); + connect(comboBoxColorInterpolationType, SIGNAL( activated(int) ), SLOT( slotChangedColorInterpolation(int) )); + connect(comboBoxInterpolationType, SIGNAL( activated(int) ), SLOT( slotChangedInterpolation(int) )); + connect(leftColorButton, SIGNAL( changed(const QColor&) ), SLOT( slotChangedLeftColor(const QColor&) )); + connect(rightColorButton, SIGNAL( changed(const QColor&) ), SLOT( slotChangedRightColor(const QColor&) )); + +// intNumInputLeftOpacity->setRange( 0, 100, false); + connect(intNumInputLeftOpacity, SIGNAL( valueChanged(int) ), SLOT( slotChangedLeftOpacity(int) )); +// intNumInputRightOpacity->setRange( 0, 100, false); + connect(intNumInputRightOpacity, SIGNAL( valueChanged(int) ), 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 = qRound(segment->startColor().alpha() * 100); + intNumInputLeftOpacity->setValue( leftOpacity ); + + int rightOpacity = qRound(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 QColor& color) +{ + KisGradientSegment* segment = gradientSlider->selectedSegment(); + if(segment) + segment->setStartColor( Color( color, segment->startColor().alpha() ) ); + gradientSlider->update(); + + paramChanged(); +} + +void KisAutogradient::slotChangedRightColor( const QColor& color) +{ + KisGradientSegment* segment = gradientSlider->selectedSegment(); + if(segment) + segment->setEndColor( Color( color, segment->endColor().alpha() ) ); + gradientSlider->repaint(); + + paramChanged(); +} + +void KisAutogradient::slotChangedLeftOpacity( int value ) +{ + KisGradientSegment* segment = gradientSlider->selectedSegment(); + if(segment) + segment->setStartColor( Color( segment->startColor().color(), (double)value / 100 ) ); + gradientSlider->repaint(false); + + paramChanged(); +} + +void KisAutogradient::slotChangedRightOpacity( int value ) +{ + KisGradientSegment* segment = gradientSlider->selectedSegment(); + if(segment) + segment->setEndColor( Color( segment->endColor().color(), (double)value / 100 ) ); + gradientSlider->repaint(false); + + paramChanged(); +} + +void KisAutogradient::paramChanged() +{ + m_autogradientResource->updatePreview (); + emit activatedResource( m_autogradientResource ); +} + +#include "kis_autogradient.moc" diff --git a/krita/ui/kis_autogradient.h b/krita/ui/kis_autogradient.h new file mode 100644 index 00000000..a2865d5e --- /dev/null +++ b/krita/ui/kis_autogradient.h @@ -0,0 +1,52 @@ +/* + * 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 + + public: + KisAutogradient(QWidget *parent, const char* name, const QString& 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 QColor& color); + void slotChangedRightColor( const QColor& color); + void slotChangedLeftOpacity( int value ); + void slotChangedRightOpacity( int value ); + void paramChanged(); +}; + +#endif diff --git a/krita/ui/kis_birdeye_box.cc b/krita/ui/kis_birdeye_box.cc new file mode 100644 index 00000000..54335f9c --- /dev/null +++ b/krita/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 "qlayout.h" +#include "qlabel.h" +#include "qpixmap.h" +#include "qpainter.h" +#include "qimage.h" +#include "config.h" +#include LCMS_HEADER +#include "klocale.h" +#include "qtooltip.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 QRect size() + { + if (!m_canvasSubject->currentImg()) return QRect(0,0,0,0); + + return QRect(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 QSize pixelSize() + { + if (!m_image) return QSize(0, 0); + return QSize(m_image->width(), m_image->height()); + } + + virtual QImage image(QRect r, QSize thumbnailSize) + { + if (!m_image || r.isEmpty() || thumbnailSize.width() == 0 || thumbnailSize.height() == 0) { + return QImage(); + } + + KisPaintDevice thumbnailRect(m_image->colorSpace(), "thumbnailRect"); + KisPaintDeviceSP mergedImage = m_image->projection(); + + Q_INT32 imageWidth = m_image->width(); + Q_INT32 imageHeight = m_image->height(); + Q_UINT32 pixelSize = m_image->colorSpace()->pixelSize(); + + for (Q_INT32 y = 0; y < r.height(); ++y) { + + KisHLineIteratorPixel it = thumbnailRect.createHLineIterator(0, y, r.width(), true); + Q_INT32 thumbnailY = r.y() + y; + Q_INT32 thumbnailX = r.x(); + Q_INT32 imageY = (thumbnailY * imageHeight) / thumbnailSize.height(); + KisHLineIteratorPixel srcIt = mergedImage -> createHLineIterator(0, imageY, imageWidth, false); + + while (!it.isDone()) { + + Q_INT32 imageX = (thumbnailX * imageWidth) / thumbnailSize.width(); + Q_INT32 dx = imageX - srcIt.x(); + srcIt += dx; + + //KisColor pixelColor = mergedImage->colorAt(imageX, imageY); + memcpy(it.rawData(), srcIt.rawData(), pixelSize); + + ++it; + ++thumbnailX; + } + } + + return thumbnailRect.convertToQImage(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, QWidget* parent, const char* name) + : QWidget(parent, name) + , m_view(view) + , m_subject(view->canvasSubject()) +{ + QVBoxLayout * l = new QVBoxLayout(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, SIGNAL(cursorPosition( Q_INT32, Q_INT32 )), m_birdEyePanel, SLOT(cursorPosChanged( Q_INT32, Q_INT32 ))); + connect(view, SIGNAL(viewTransformationsChanged()), m_birdEyePanel, SLOT(slotViewTransformationChanged())); + + l->addWidget(m_birdEyePanel); + + QHBoxLayout * hl = new QHBoxLayout(l); + + m_exposureLabel = new QLabel(i18n("Exposure:"), this); + hl->addWidget(m_exposureLabel); + + m_exposureDoubleWidget = new KisDoubleWidget(-10, 10, this); + m_exposureDoubleWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + hl->addWidget(m_exposureDoubleWidget); + QToolTip::add(m_exposureDoubleWidget, i18n("Select the exposure (stops) for HDR images")); + l->addItem(new QSpacerItem(0, 1, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding)); + + m_exposureDoubleWidget->setPrecision(1); + m_exposureDoubleWidget->setValue(0); + m_exposureDoubleWidget->setLineStep(0.1); + m_exposureDoubleWidget->setPageStep(1); + + connect(m_exposureDoubleWidget, SIGNAL(valueChanged(double)), SLOT(exposureValueChanged(double))); + connect(m_exposureDoubleWidget, SIGNAL(sliderPressed()), SLOT(exposureSliderPressed())); + connect(m_exposureDoubleWidget, SIGNAL(sliderReleased()), SLOT(exposureSliderReleased())); + + m_draggingExposureSlider = false; + + Q_ASSERT(m_subject->document() != 0); + connect(m_subject->document(), SIGNAL(sigCommandExecuted()), SLOT(slotDocCommandExecuted())); + + if (m_image) { + connect(m_image, SIGNAL(sigImageUpdated(QRect)), SLOT(slotImageUpdated(QRect))); + } +} + +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, SIGNAL(sigImageUpdated(QRect)), SLOT(slotImageUpdated(QRect))); + connect(m_image, SIGNAL(sigSizeChanged(Q_INT32, Q_INT32)), SLOT(slotImageSizeChanged(Q_INT32, Q_INT32))); + connect(m_image, SIGNAL(sigColorSpaceChanged(KisColorSpace *)), 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 = QRect(); + } +} + +void KisBirdEyeBox::slotImageUpdated(QRect r) +{ + m_dirtyRect |= r; +} + +void KisBirdEyeBox::slotImageSizeChanged(Q_INT32 /*w*/, Q_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/krita/ui/kis_birdeye_box.h b/krita/ui/kis_birdeye_box.h new file mode 100644 index 00000000..46b6d72d --- /dev/null +++ b/krita/ui/kis_birdeye_box.h @@ -0,0 +1,68 @@ +/* + * 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 "qwidget.h" + +#include "kis_types.h" + +class KoBirdEyePanel; +class KisDoubleWidget; +class KisView; +class KisCanvasSubject; +class KoZoomAdapter; +class KisColorSpace; + +class KisBirdEyeBox : public QWidget +{ + Q_OBJECT + +public: + + KisBirdEyeBox(KisView * view, QWidget * parent = 0, const char* name=0); + ~KisBirdEyeBox(); + + void setImage(KisImageSP image); + +public slots: + void slotDocCommandExecuted(); + void slotImageUpdated(QRect r); + void slotImageSizeChanged(Q_INT32 w, Q_INT32 h); + void slotImageColorSpaceChanged(KisColorSpace *cs); + +protected slots: + void exposureValueChanged(double exposure); + void exposureSliderPressed(); + void exposureSliderReleased(); + +private: + KoBirdEyePanel * m_birdEyePanel; + KisDoubleWidget * m_exposureDoubleWidget; + QLabel *m_exposureLabel; + KisView * m_view; + KisCanvasSubject * m_subject; + bool m_draggingExposureSlider; + KoZoomAdapter * m_zoomAdapter; + KisImageSP m_image; + QRect m_dirtyRect; +}; + +#endif // KIS_BIRDEYE_BOX_H diff --git a/krita/ui/kis_boundary_painter.cc b/krita/ui/kis_boundary_painter.cc new file mode 100644 index 00000000..b8dfc761 --- /dev/null +++ b/krita/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" + +QPixmap KisBoundaryPainter::createPixmap(const KisBoundary& boundary, int w, int h) +{ + QPixmap target(w, h); + KisCanvasPainter painter(&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(); + + // 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; + } + + // 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/krita/ui/kis_boundary_painter.h b/krita/ui/kis_boundary_painter.h new file mode 100644 index 00000000..10665ee9 --- /dev/null +++ b/krita/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 QPixmap createPixmap(const KisBoundary& boundary, int w, int h); +}; + +#endif // _KIS_BOUNDARY_PAINTER_H_ + diff --git a/krita/ui/kis_brush_chooser.cc b/krita/ui/kis_brush_chooser.cc new file mode 100644 index 00000000..03f6c502 --- /dev/null +++ b/krita/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(QWidget *parent, const char *name) + : super(parent, name) +{ + m_lbSpacing = new QLabel(i18n("Spacing:"), this); + m_slSpacing = new KisDoubleWidget(0.0, 10, this, "double_widget"); + m_slSpacing->setTickmarks(QSlider::Below); + m_slSpacing->setTickInterval(1); + QObject::connect(m_slSpacing, SIGNAL(valueChanged(double)), this, SLOT(slotSetItemSpacing(double))); + + m_chkColorMask = new QCheckBox(i18n("Use color as mask"), this); + QObject::connect(m_chkColorMask, SIGNAL(toggled(bool)), this, SLOT(slotSetItemUseColorAsMask(bool))); + + m_lbName = new QLabel(this); + + QVBoxLayout *mainLayout = new QVBoxLayout(this, 2, -1, "main layout"); + + mainLayout->addWidget(m_lbName); + mainLayout->addWidget(chooserWidget(), 10); + + QGridLayout *spacingLayout = new QGridLayout( 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()); + + QString text = QString("%1 (%2 x %3)").arg(brush->name()).arg(brush->width()).arg(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/krita/ui/kis_brush_chooser.h b/krita/ui/kis_brush_chooser.h new file mode 100644 index 00000000..942742d1 --- /dev/null +++ b/krita/ui/kis_brush_chooser.h @@ -0,0 +1,51 @@ +/* + * 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 QLabel; +class QCheckBox; + +class KisDoubleWidget; + +class KisBrushChooser : public KisItemChooser { + typedef KisItemChooser super; + Q_OBJECT + +public: + KisBrushChooser(QWidget *parent = 0, const char *name = 0); + virtual ~KisBrushChooser(); + +protected: + virtual void update(KoIconItem *item); + +private slots: + void slotSetItemSpacing(double spacing); + void slotSetItemUseColorAsMask(bool); + +private: + QLabel *m_lbName; + QLabel *m_lbSpacing; + KisDoubleWidget *m_slSpacing; + QCheckBox *m_chkColorMask; +}; + +#endif // KIS_BRUSH_CHOOSER_H_ + diff --git a/krita/ui/kis_button_event.h b/krita/ui/kis_button_event.h new file mode 100644 index 00000000..e8b7fc2b --- /dev/null +++ b/krita/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: + Qt::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, + Qt::ButtonState button, + Qt::ButtonState state) + : super(type, device, pos, globalPos, pressure, xTilt, yTilt, state) + , m_button(button) {} + + Qt::ButtonState m_button; +}; + +#endif // KIS_BUTTON_EVENT_H_ + diff --git a/krita/ui/kis_button_press_event.h b/krita/ui/kis_button_press_event.h new file mode 100644 index 00000000..51ad0d66 --- /dev/null +++ b/krita/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, Qt::ButtonState button, Qt::ButtonState state) : super(ButtonPressEvent, device, pos, globalPos, pressure, xTilt, yTilt, button, state) {} +}; + +#endif // KIS_BUTTON_PRESS_EVENT_H_ + diff --git a/krita/ui/kis_button_release_event.h b/krita/ui/kis_button_release_event.h new file mode 100644 index 00000000..3d9234f0 --- /dev/null +++ b/krita/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, Qt::ButtonState button, Qt::ButtonState state) : super(ButtonReleaseEvent, device, pos, globalPos, pressure, xTilt, yTilt, button, state) {} +}; + +#endif // KIS_BUTTON_RELEASE_EVENT_H_ + diff --git a/krita/ui/kis_canvas.cc b/krita/ui/kis_canvas.cc new file mode 100644 index 00000000..499f4c29 --- /dev/null +++ b/krita/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 Qt 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 Qt 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.QPL 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 Qt Enterprise Edition or Qt Professional Edition +** licenses for Unix/X11 may use this file in accordance with the Qt 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 Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL 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(QPaintEvent *e) +{ + emit sigGotPaintEvent(e); +} + +void KisCanvasWidget::widgetGotMousePressEvent(QMouseEvent *e) +{ + KisButtonPressEvent ke(KisInputDevice::mouse(), e->pos(), e->globalPos(), PRESSURE_DEFAULT, 0, 0, e->button(), e->state()); + buttonPressEvent(&ke); +} + +void KisCanvasWidget::widgetGotMouseReleaseEvent(QMouseEvent *e) +{ + KisButtonReleaseEvent ke(KisInputDevice::mouse(), e->pos(), e->globalPos(), PRESSURE_DEFAULT, 0, 0, e->button(), e->state()); + buttonReleaseEvent(&ke); +} + +void KisCanvasWidget::widgetGotMouseDoubleClickEvent(QMouseEvent *e) +{ + KisDoubleClickEvent ke(KisInputDevice::mouse(), e->pos(), e->globalPos(), PRESSURE_DEFAULT, 0, 0, e->button(), e->state()); + doubleClickEvent(&ke); +} + +void KisCanvasWidget::widgetGotMouseMoveEvent(QMouseEvent *e) +{ + KisMoveEvent ke(KisInputDevice::mouse(), e->pos(), e->globalPos(), PRESSURE_DEFAULT, 0, 0, e->state()); + moveEvent(&ke); +} + +void KisCanvasWidget::widgetGotTabletEvent(QTabletEvent *e) +{ + KisInputDevice device; + + switch (e->device()) { + default: + case QTabletEvent::NoDevice: + case QTabletEvent::Stylus: + device = KisInputDevice::stylus(); + break; + case QTabletEvent::Puck: + device = KisInputDevice::puck(); + break; + case QTabletEvent::Eraser: + device = KisInputDevice::eraser(); + break; + } + + double pressure = e->pressure() / 255.0; + + if (e->type() == QEvent::TabletPress) { + KisButtonPressEvent ke(device, e->pos(), e->globalPos(), pressure, e->xTilt(), e->yTilt(), Qt::LeftButton, Qt::NoButton); + translateTabletEvent(&ke); + } + else + if (e->type() == QEvent::TabletRelease) { + KisButtonReleaseEvent ke(device, e->pos(), e->globalPos(), pressure, e->xTilt(), e->yTilt(), Qt::LeftButton, Qt::NoButton); + translateTabletEvent(&ke); + } + else { + KisMoveEvent ke(device, e->pos(), 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 Qt does not get to see them. This breaks + // the tablet event accept/ignore mechanism, causing Qt to consume the first + // mouse button event it sees, instead of a mouse move. 'Ignoring' tablet move events + // stops Qt 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(QEvent *e) +{ + emit sigGotEnterEvent(e); +} + +void KisCanvasWidget::widgetGotLeaveEvent(QEvent *e) +{ + emit sigGotLeaveEvent(e); +} + +void KisCanvasWidget::widgetGotWheelEvent(QWheelEvent *e) +{ + emit sigGotMouseWheelEvent(e); +} + +void KisCanvasWidget::widgetGotKeyPressEvent(QKeyEvent *e) +{ + emit sigGotKeyPressEvent(e); +} + +void KisCanvasWidget::widgetGotKeyReleaseEvent(QKeyEvent *e) +{ + emit sigGotKeyReleaseEvent(e); +} + +void KisCanvasWidget::widgetGotDragEnterEvent(QDragEnterEvent *e) +{ + emit sigGotDragEnterEvent(e); +} + +void KisCanvasWidget::widgetGotDropEvent(QDropEvent *e) +{ + emit sigGotDropEvent(e); +} + +void KisCanvasWidget::moveEvent(KisMoveEvent *e) +{ + emit sigGotMoveEvent(e); +} + +void KisCanvasWidget::buttonPressEvent(KisButtonPressEvent *e) +{ + QWidget *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 = QApplication::desktop()->x11Display(); + + // Look at the modifier mapping and get the correct masks for alt/meta + XModifierKeymap *map = XGetModifierMapping(x11Display); + + if (map) { + int mapIndex = 0; + + for (int maskIndex = 0; maskIndex < 8; maskIndex++) { + 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 << maskIndex; + } + if (X11MetaMask == 0 && (sym == XK_Meta_L || sym == XK_Meta_R)) { + X11MetaMask = 1 << maskIndex; + } + } + + 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(); + + QString lowerCaseName = tabletDevice.name().lower(); + + // Find the devices that Qt 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 +} + +Qt::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 |= Qt::ShiftButton; + if (state & ControlMask) + buttonState |= Qt::ControlButton; + if (state & X11AltMask) + buttonState |= Qt::AltButton; + if (state & X11MetaMask) + buttonState |= Qt::MetaButton; + + return static_cast(buttonState); +} + +Qt::ButtonState KisCanvasWidget::translateX11Button(unsigned int X11Button) +{ + Qt::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(QApplication::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 Qt 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; +} + +Q_INT32 KisCanvasWidget::X11TabletDevice::numAxes() const +{ + return m_axisInfo.count(); +} + +void KisCanvasWidget::X11TabletDevice::setXAxis(Q_INT32 axis) +{ + m_xAxis = axis; +} + +void KisCanvasWidget::X11TabletDevice::setYAxis(Q_INT32 axis) +{ + m_yAxis = axis; +} + +void KisCanvasWidget::X11TabletDevice::setPressureAxis(Q_INT32 axis) +{ + m_pressureAxis = axis; +} + +void KisCanvasWidget::X11TabletDevice::setXTiltAxis(Q_INT32 axis) +{ + m_xTiltAxis = axis; +} + +void KisCanvasWidget::X11TabletDevice::setYTiltAxis(Q_INT32 axis) +{ + m_yTiltAxis = axis; +} + +void KisCanvasWidget::X11TabletDevice::setWheelAxis(Q_INT32 axis) +{ + m_wheelAxis = axis; +} + +void KisCanvasWidget::X11TabletDevice::setToolIDAxis(Q_INT32 axis) +{ + m_toolIDAxis = axis; +} + +void KisCanvasWidget::X11TabletDevice::setSerialNumberAxis(Q_INT32 axis) +{ + m_serialNumberAxis = axis; +} + +Q_INT32 KisCanvasWidget::X11TabletDevice::xAxis() const +{ + return m_xAxis; +} + +Q_INT32 KisCanvasWidget::X11TabletDevice::yAxis() const +{ + return m_yAxis; +} + +Q_INT32 KisCanvasWidget::X11TabletDevice::pressureAxis() const +{ + return m_pressureAxis; +} + +Q_INT32 KisCanvasWidget::X11TabletDevice::xTiltAxis() const +{ + return m_xTiltAxis; +} + +Q_INT32 KisCanvasWidget::X11TabletDevice::yTiltAxis() const +{ + return m_yTiltAxis; +} + +Q_INT32 KisCanvasWidget::X11TabletDevice::wheelAxis() const +{ + return m_wheelAxis; +} + +Q_INT32 KisCanvasWidget::X11TabletDevice::toolIDAxis() const +{ + return m_toolIDAxis; +} + +Q_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(QWidget *widget) const +{ + if (!m_eventClassList.isEmpty()) { + int result = XSelectExtensionEvent(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, + Q_UINT32 toolID, Q_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); + Q_UINT32 toolID = 0; + Q_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 = (Q_INT16)(axisData[m_xTiltAxis] & 0xffff); + toolID = ((Q_UINT32)axisData[m_xTiltAxis] >> 16) & 0xffff; + + tilt.setX(translateAxisValue(xTiltAxisValue, m_axisInfo[m_xTiltAxis])); + } + + if (m_yTiltAxis != NoAxis) { + int yTiltAxisValue = (Q_INT16)(axisData[m_yTiltAxis] & 0xffff); + serialNumber = (Q_UINT32)axisData[m_yTiltAxis] & 0xffff0000; + + tilt.setY(translateAxisValue(yTiltAxisValue, m_axisInfo[m_yTiltAxis])); + } + + double wheel = 0; + + if (m_wheelAxis != NoAxis) { + int wheelAxisValue = (Q_INT16)(axisData[m_wheelAxis] & 0xffff); + serialNumber |= ((Q_UINT32)axisData[m_wheelAxis] >> 16) & 0xffff; + + wheel = translateAxisValue(wheelAxisValue, m_axisInfo[m_wheelAxis]); + } + + //QString 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(QWidget *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, QPoint widgetOriginPos) +{ + if (event->type == MotionNotify) { + // Mouse move + if (!m_enableMoveEventCompressionHint) { + + XMotionEvent motion = event->xmotion; + QPoint globalPos(motion.x_root, motion.y_root); + + if (globalPos.x() != m_lastRootX || globalPos.y() != m_lastRootY) { + + int state = translateX11ButtonState(motion.state); + QPoint pos(motion.x, motion.y); + QMouseEvent e(QEvent::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; + Qt::ButtonState button; + Qt::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 (QApplication::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 (QApplication::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 + QDesktopWidget *desktop = QApplication::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 Qt will + // process it and send a QTabletEvent. + 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(QApplication::desktop()->x11Display(), + tabletDevice.xDevice()); + + // If your the laptop sleeps, and you remove the mouse from the usb + // port, then on wake-up Krita 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 QPAINTDEVICE_CANVAS_WIDGET false +#define OPENGL_CANVAS_WIDGET true + +KisCanvas::KisCanvas(QWidget *parent, const char *name) +{ + m_parent = parent; + m_name = name; + m_enableMoveEventCompressionHint = false; + m_canvasWidget = 0; + m_useOpenGL = false; + createCanvasWidget(QPAINTDEVICE_CANVAS_WIDGET); +} + +KisCanvas::~KisCanvas() +{ + delete m_canvasWidget; +} + +#ifdef HAVE_GL +void KisCanvas::createCanvasWidget(bool useOpenGL, QGLWidget *sharedContextWidget) +#else +void KisCanvas::createCanvasWidget(bool useOpenGL) +#endif +{ + delete m_canvasWidget; + +#ifndef HAVE_GL + useOpenGL = false; +#else + if (useOpenGL && !QGLFormat::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 KisQPaintDeviceCanvasWidget(m_parent, m_name.latin1()); + } + + m_useOpenGL = useOpenGL; + + Q_CHECK_PTR(m_canvasWidget); + QWidget *widget = dynamic_cast(m_canvasWidget); + + widget->setBackgroundMode(QWidget::NoBackground); + widget->setMouseTracking(true); + widget->setAcceptDrops(true); + m_canvasWidget->enableMoveEventCompressionHint(m_enableMoveEventCompressionHint); + +#if defined(EXTENDED_X11_TABLET_SUPPORT) + selectTabletDeviceEvents(); +#endif + + connect(m_canvasWidget, SIGNAL(sigGotPaintEvent(QPaintEvent *)), SIGNAL(sigGotPaintEvent(QPaintEvent *))); + connect(m_canvasWidget, SIGNAL(sigGotEnterEvent(QEvent*)), SIGNAL(sigGotEnterEvent(QEvent*))); + connect(m_canvasWidget, SIGNAL(sigGotLeaveEvent(QEvent*)), SIGNAL(sigGotLeaveEvent(QEvent*))); + connect(m_canvasWidget, SIGNAL(sigGotMouseWheelEvent(QWheelEvent*)), SIGNAL(sigGotMouseWheelEvent(QWheelEvent*))); + connect(m_canvasWidget, SIGNAL(sigGotKeyPressEvent(QKeyEvent*)), SIGNAL(sigGotKeyPressEvent(QKeyEvent*))); + connect(m_canvasWidget, SIGNAL(sigGotKeyReleaseEvent(QKeyEvent*)), SIGNAL(sigGotKeyReleaseEvent(QKeyEvent*))); + connect(m_canvasWidget, SIGNAL(sigGotDragEnterEvent(QDragEnterEvent*)), SIGNAL(sigGotDragEnterEvent(QDragEnterEvent*))); + connect(m_canvasWidget, SIGNAL(sigGotDropEvent(QDropEvent*)), SIGNAL(sigGotDropEvent(QDropEvent*))); + connect(m_canvasWidget, SIGNAL(sigGotMoveEvent(KisMoveEvent *)), SIGNAL(sigGotMoveEvent(KisMoveEvent *))); + connect(m_canvasWidget, SIGNAL(sigGotButtonPressEvent(KisButtonPressEvent *)), SIGNAL(sigGotButtonPressEvent(KisButtonPressEvent *))); + connect(m_canvasWidget, SIGNAL(sigGotButtonReleaseEvent(KisButtonReleaseEvent *)), SIGNAL(sigGotButtonReleaseEvent(KisButtonReleaseEvent *))); + connect(m_canvasWidget, SIGNAL(sigGotDoubleClickEvent(KisDoubleClickEvent *)), SIGNAL(sigGotDoubleClickEvent(KisDoubleClickEvent *))); +} + +void KisCanvas::createQPaintDeviceCanvas() +{ + createCanvasWidget(QPAINTDEVICE_CANVAS_WIDGET); +} + +#ifdef HAVE_GL +void KisCanvas::createOpenGLCanvas(QGLWidget *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); + } +} + +QWidget *KisCanvas::QPaintDeviceWidget() const +{ + if (m_useOpenGL) { + return 0; + } else { + return dynamic_cast(m_canvasWidget); + } +} + +#ifdef HAVE_GL +QGLWidget *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 QRect& 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::repaint() +{ + Q_ASSERT(m_canvasWidget); + dynamic_cast(m_canvasWidget)->repaint(); +} + +void KisCanvas::repaint(bool erase) +{ + Q_ASSERT(m_canvasWidget); + dynamic_cast(m_canvasWidget)->repaint(erase); +} + +void KisCanvas::repaint(int x, int y, int width, int height, bool erase) +{ + Q_ASSERT(m_canvasWidget); + dynamic_cast(m_canvasWidget)->repaint(x, y, width, height, erase); +} + +void KisCanvas::repaint(const QRect& r, bool erase) +{ + Q_ASSERT(m_canvasWidget); + dynamic_cast(m_canvasWidget)->repaint(r, erase); +} + +void KisCanvas::repaint(const QRegion& r, bool erase) +{ + Q_ASSERT(m_canvasWidget); + dynamic_cast(m_canvasWidget)->repaint(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(QWidget::FocusPolicy focusPolicy) +{ + Q_ASSERT(m_canvasWidget); + dynamic_cast(m_canvasWidget)->setFocusPolicy(focusPolicy); +} + +const QCursor& KisCanvas::cursor() const +{ + Q_ASSERT(m_canvasWidget); + return dynamic_cast(m_canvasWidget)->cursor(); +} + +void KisCanvas::setCursor(const QCursor& 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 (QApplication::activePopupWidget() != 0) { + return false; + } + if (QApplication::activeModalWidget() != 0) { + return false; + } + + QWidget *canvasWidget = dynamic_cast(m_canvasWidget); + Q_ASSERT(canvasWidget != 0); + + if (canvasWidget) { + if (QApplication::widgetAt(QCursor::pos(), true) == canvasWidget) { + return true; + } + } + return false; +} + +void KisCanvas::handleKeyEvent(QEvent *e) +{ + QKeyEvent *ke = dynamic_cast(e); + + Q_ASSERT(ke != 0); + + if (ke) { + QWidget *canvasWidget = dynamic_cast(m_canvasWidget); + Q_ASSERT(canvasWidget != 0); + + if (canvasWidget) { + canvasWidget->setFocus(); + + if (e->type() == QEvent::KeyPress) { + emit sigGotKeyPressEvent(ke); + } else { + emit sigGotKeyReleaseEvent(ke); + } + } + } +} + +#include "kis_canvas.moc" + diff --git a/krita/ui/kis_canvas.h b/krita/ui/kis_canvas.h new file mode 100644 index 00000000..b9e38738 --- /dev/null +++ b/krita/ui/kis_canvas.h @@ -0,0 +1,381 @@ +/* + * 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_WS_X11 + +// Irix has a different (and better) XInput tablet driver to +// the XFree/xorg driver. Qt 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 QObject { + Q_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(QWidget *widget); +#endif + +#ifdef Q_WS_X11 + static void initX11Support(); +#endif + +signals: + void sigGotPaintEvent(QPaintEvent*); + void sigGotEnterEvent(QEvent*); + void sigGotLeaveEvent(QEvent*); + void sigGotMouseWheelEvent(QWheelEvent*); + void sigGotKeyPressEvent(QKeyEvent*); + void sigGotKeyReleaseEvent(QKeyEvent*); + void sigGotDragEnterEvent(QDragEnterEvent*); + void sigGotDropEvent(QDropEvent*); + void sigGotMoveEvent(KisMoveEvent *); + void sigGotButtonPressEvent(KisButtonPressEvent *); + void sigGotButtonReleaseEvent(KisButtonReleaseEvent *); + void sigGotDoubleClickEvent(KisDoubleClickEvent *); + +protected: + void widgetGotPaintEvent(QPaintEvent *event); + void widgetGotMousePressEvent(QMouseEvent *event); + void widgetGotMouseReleaseEvent(QMouseEvent *event); + void widgetGotMouseDoubleClickEvent(QMouseEvent *event); + void widgetGotMouseMoveEvent(QMouseEvent *event); + void widgetGotTabletEvent(QTabletEvent *event); + void widgetGotEnterEvent(QEvent *event ); + void widgetGotLeaveEvent(QEvent *event); + void widgetGotWheelEvent(QWheelEvent *event); + void widgetGotKeyPressEvent(QKeyEvent *event); + void widgetGotKeyReleaseEvent(QKeyEvent *event); + void widgetGotDragEnterEvent(QDragEnterEvent *event); + void widgetGotDropEvent(QDropEvent *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, Qt 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, QPoint widgetOriginPos); + static Qt::ButtonState translateX11ButtonState(int state); + static Qt::ButtonState translateX11Button(unsigned int button); + + static bool X11SupportInitialised; + + // Modifier masks 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; } + QString 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; + + Q_INT32 numAxes() const; + + void setXAxis(Q_INT32 axis); + void setYAxis(Q_INT32 axis); + void setPressureAxis(Q_INT32 axis); + void setXTiltAxis(Q_INT32 axis); + void setYTiltAxis(Q_INT32 axis); + void setWheelAxis(Q_INT32 axis); + void setToolIDAxis(Q_INT32 axis); + void setSerialNumberAxis(Q_INT32 axis); + + static const Q_INT32 NoAxis = -1; + static const Q_INT32 DefaultAxis = -2; + + Q_INT32 xAxis() const; + Q_INT32 yAxis() const; + Q_INT32 pressureAxis() const; + Q_INT32 xTiltAxis() const; + Q_INT32 yTiltAxis() const; + Q_INT32 wheelAxis() const; + Q_INT32 toolIDAxis() const; + Q_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(QWidget *widget) const; + + class State + { + public: + State() {} + State(const KisPoint& pos, double pressure, const KisVector2D& tilt, double wheel, + Q_UINT32 toolID, Q_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. + Q_UINT32 toolID() const { return m_toolID; } + Q_UINT32 serialNumber() const { return m_serialNumber; } + + private: + KisPoint m_pos; + double m_pressure; + KisVector2D m_tilt; + double m_wheel; + Q_UINT32 m_toolID; + Q_UINT32 m_serialNumber; + }; + + State translateAxisData(const int *axisData) const; + + private: + double translateAxisValue(int value, const XAxisInfo& axisInfo) const; + + XID m_deviceId; + XDevice *m_XDevice; + + QString m_name; + + bool m_mightBeTabletDevice; + KisInputDevice m_inputDevice; + + bool m_enabled; + + Q_INT32 m_xAxis; + Q_INT32 m_yAxis; + Q_INT32 m_pressureAxis; + Q_INT32 m_xTiltAxis; + Q_INT32 m_yTiltAxis; + Q_INT32 m_wheelAxis; + Q_INT32 m_toolIDAxis; + Q_INT32 m_serialNumberAxis; + + QValueVector m_axisInfo; + + int m_motionNotifyEvent; + int m_buttonPressEvent; + int m_buttonReleaseEvent; + int m_proximityInEvent; + int m_proximityOutEvent; + + QValueVector 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 QObject { + Q_OBJECT + +public: + KisCanvas(QWidget *parent, 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(QEvent *e); + + int width() const; + int height() const; + + void update(); + void update(const QRect& r); + void update(int x, int y, int width, int height); + void repaint(); + void repaint(bool erase); + void repaint(int x, int y, int width, int height, bool erase = true); + void repaint(const QRect& r, bool erase = true); + void repaint(const QRegion& r, bool erase = true); + + void updateGeometry(); + +#if defined(EXTENDED_X11_TABLET_SUPPORT) + void selectTabletDeviceEvents(); +#endif + +signals: + void sigGotPaintEvent(QPaintEvent*); + void sigGotEnterEvent(QEvent*); + void sigGotLeaveEvent(QEvent*); + void sigGotMouseWheelEvent(QWheelEvent*); + void sigGotKeyPressEvent(QKeyEvent*); + void sigGotKeyReleaseEvent(QKeyEvent*); + void sigGotDragEnterEvent(QDragEnterEvent*); + void sigGotDropEvent(QDropEvent*); + 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 Qt3, using a QPainter on + // a QGLWidget is not reliable. + QWidget *QPaintDeviceWidget() const; +#ifdef HAVE_GL + QGLWidget *OpenGLWidget() const; +#endif + void createQPaintDeviceCanvas(); +#ifdef HAVE_GL + void createOpenGLCanvas(QGLWidget *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(QWidget::FocusPolicy focusPolicy); + + const QCursor& cursor() const; + void setCursor(const QCursor& cursor); + + KisCanvasWidgetPainter *createPainter(); + KisCanvasWidget *canvasWidget() const; + +protected: +#ifdef HAVE_GL + void createCanvasWidget(bool useOpenGL, QGLWidget *sharedContextWidget = 0); +#else + void createCanvasWidget(bool useOpenGL); +#endif + QWidget *m_parent; + QString m_name; + KisCanvasWidget *m_canvasWidget; + bool m_enableMoveEventCompressionHint; + bool m_useOpenGL; +}; + +#endif // KIS_CANVAS_H_ + diff --git a/krita/ui/kis_canvas_painter.cc b/krita/ui/kis_canvas_painter.cc new file mode 100644 index 00000000..f9103e65 --- /dev/null +++ b/krita/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() +{ +} + +QFontMetrics KisCanvasWidgetPainter::fontMetrics() const +{ + return QFontMetrics(QFont()); +} + +QFontInfo KisCanvasWidgetPainter::fontInfo() const +{ + return QFontInfo(QFont()); +} + +const QFont& KisCanvasWidgetPainter::font() const +{ + return m_defaultFont; +} + +void KisCanvasWidgetPainter::setFont(const QFont& /*font*/) +{ +} + +const QPen& KisCanvasWidgetPainter::pen() const +{ + return m_defaultPen; +} + +void KisCanvasWidgetPainter::setPen(const QPen& /*pen*/) +{ +} + +void KisCanvasWidgetPainter::setPen(Qt::PenStyle /*penStyle*/) +{ +} + +void KisCanvasWidgetPainter::setPen(const QColor& /*color*/) +{ +} + +const QBrush& KisCanvasWidgetPainter::brush() const +{ + return m_defaultBrush; +} + +void KisCanvasWidgetPainter::setBrush(const QBrush& /*brush*/) +{ +} + +void KisCanvasWidgetPainter::setBrush(Qt::BrushStyle /*brushStyle*/) +{ +} + +void KisCanvasWidgetPainter::setBrush(const QColor& /*color*/) +{ +} + +QPoint KisCanvasWidgetPainter::pos() const +{ + return QPoint(); +} + +const QColor& KisCanvasWidgetPainter::backgroundColor() const +{ + return m_defaultColor; +} + +void KisCanvasWidgetPainter::setBackgroundColor(const QColor& /*color*/) +{ +} + +Qt::Qt::BGMode KisCanvasWidgetPainter::backgroundMode() const +{ + return Qt::TransparentMode; +} + +void KisCanvasWidgetPainter::setBackgroundMode(Qt::Qt::BGMode /*bgMode*/) +{ +} + +Qt::Qt::RasterOp KisCanvasWidgetPainter::rasterOp() const +{ + return Qt::CopyROP; +} + +void KisCanvasWidgetPainter::setRasterOp(Qt::RasterOp /*rasterOp*/) +{ +} + +const QPoint& KisCanvasWidgetPainter::brushOrigin() const +{ + return m_defaultBrushOrigin; +} + +void KisCanvasWidgetPainter::setBrushOrigin(int /*x*/, int /*y*/) +{ +} + +void KisCanvasWidgetPainter::setBrushOrigin(const QPoint& /*origin*/) +{ +} + +bool KisCanvasWidgetPainter::hasViewXForm() const +{ + return false; +} + +bool KisCanvasWidgetPainter::hasWorldXForm() const +{ + return false; +} + +void KisCanvasWidgetPainter::setViewXForm(bool /*enable*/) +{ +} + +QRect KisCanvasWidgetPainter::window() const +{ + return QRect(); +} + +void KisCanvasWidgetPainter::setWindow(const QRect& /*r*/) +{ +} + +void KisCanvasWidgetPainter::setWindow(int /*x*/, int /*y*/, int /*w*/, int /*h*/) +{ +} + +QRect KisCanvasWidgetPainter::viewport() const +{ + return QRect(); +} + +void KisCanvasWidgetPainter::setViewport(const QRect& /*r*/) +{ +} + +void KisCanvasWidgetPainter::setViewport(int /*x*/, int /*y*/, int /*w*/, int /*h*/) +{ +} + + +void KisCanvasWidgetPainter::setWorldXForm(bool /*enable*/) +{ +} + +const QWMatrix& KisCanvasWidgetPainter::worldMatrix() const +{ + return m_defaultWorldMatrix; +} + +void KisCanvasWidgetPainter::setWorldMatrix(const QWMatrix& /*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; +} + +QPoint KisCanvasWidgetPainter::xForm(const QPoint& point) const +{ + return point; +} + +QRect KisCanvasWidgetPainter::xForm(const QRect& r) const +{ + return r; +} + +QPointArray KisCanvasWidgetPainter::xForm(const QPointArray& pointArray) const +{ + return pointArray; +} + +QPointArray KisCanvasWidgetPainter::xForm(const QPointArray& pointArray, int /*index*/, int /*npoints*/) const +{ + return pointArray; +} + +QPoint KisCanvasWidgetPainter::xFormDev(const QPoint& point) const +{ + return point; +} + +QRect KisCanvasWidgetPainter::xFormDev(const QRect& r) const +{ + return r; +} + +QPointArray KisCanvasWidgetPainter::xFormDev(const QPointArray& pointArray) const +{ + return pointArray; +} + +QPointArray KisCanvasWidgetPainter::xFormDev(const QPointArray& pointArray, int /*index*/, int /*npoints*/) const +{ + return pointArray; +} + +void KisCanvasWidgetPainter::setClipping(bool /*enable*/) +{ +} + +bool KisCanvasWidgetPainter::hasClipping() const +{ + return true; +} + +QRegion KisCanvasWidgetPainter::clipRegion(QPainter::CoordinateMode /*mode*/) const +{ + return QRegion(); +} + +void KisCanvasWidgetPainter::setClipRect(const QRect& /*r*/, QPainter::CoordinateMode /*mode*/) +{ +} + +void KisCanvasWidgetPainter::setClipRect(int /*x*/, int /*y*/, int /*w*/, int /*h*/, QPainter::CoordinateMode /*mode*/) +{ +} + +void KisCanvasWidgetPainter::setClipRegion(const QRegion& /*rgn*/, QPainter::CoordinateMode /*mode*/) +{ +} + +void KisCanvasWidgetPainter::drawPoint(int /*x*/, int /*y*/) +{ +} + +void KisCanvasWidgetPainter::drawPoint(const QPoint& /*point*/) +{ +} + +void KisCanvasWidgetPainter::drawPoints(const QPointArray& /*pointArray*/, int /*index*/, int /*npoints*/) +{ +} + +void KisCanvasWidgetPainter::moveTo(int /*x*/, int /*y*/) +{ +} + +void KisCanvasWidgetPainter::moveTo(const QPoint& /*point*/) +{ +} + +void KisCanvasWidgetPainter::lineTo(int /*x*/, int /*y*/) +{ +} + +void KisCanvasWidgetPainter::lineTo(const QPoint& /*point*/) +{ +} + +void KisCanvasWidgetPainter::drawLine(int /*x1*/, int /*y1*/, int /*x2*/, int /*y2*/) +{ +} + +void KisCanvasWidgetPainter::drawLine(const QPoint& /*start*/, const QPoint& /*end*/) +{ +} + +void KisCanvasWidgetPainter::drawRect(int /*x*/, int /*y*/, int /*w*/, int /*h*/) +{ +} + +void KisCanvasWidgetPainter::drawRect(const QRect& /*r*/) +{ +} + +void KisCanvasWidgetPainter::drawWinFocusRect(int /*x*/, int /*y*/, int /*w*/, int /*h*/) +{ +} + +void KisCanvasWidgetPainter::drawWinFocusRect(int /*x*/, int /*y*/, int /*w*/, int /*h*/, const QColor& /*bgColor*/) +{ +} + +void KisCanvasWidgetPainter::drawWinFocusRect(const QRect& /*r*/) +{ +} + +void KisCanvasWidgetPainter::drawWinFocusRect(const QRect& /*r*/, const QColor& /*bgColor*/) +{ +} + +void KisCanvasWidgetPainter::drawRoundRect(int /*x*/, int /*y*/, int /*w*/, int /*h*/, int /*xRnd*/, int /*yRnd*/) +{ +} + +void KisCanvasWidgetPainter::drawRoundRect(const QRect& /*r*/, int /*xRnd*/, int /*yRnd*/) +{ +} + +void KisCanvasWidgetPainter::drawEllipse(int /*x*/, int /*y*/, int /*w*/, int /*h*/) +{ +} + +void KisCanvasWidgetPainter::drawEllipse(const QRect& /*r*/) +{ +} + +void KisCanvasWidgetPainter::drawArc(int /*x*/, int /*y*/, int /*w*/, int /*h*/, int /*a*/, int /*alen*/) +{ +} + +void KisCanvasWidgetPainter::drawArc(const QRect& /*r*/, int /*a*/, int /*alen*/) +{ +} + +void KisCanvasWidgetPainter::drawPie(int /*x*/, int /*y*/, int /*w*/, int /*h*/, int /*a*/, int /*alen*/) +{ +} + +void KisCanvasWidgetPainter::drawPie(const QRect& /*r*/, int /*a*/, int /*alen*/) +{ +} + +void KisCanvasWidgetPainter::drawChord(int /*x*/, int /*y*/, int /*w*/, int /*h*/, int /*a*/, int /*alen*/) +{ +} + +void KisCanvasWidgetPainter::drawChord(const QRect& /*r*/, int /*a*/, int /*alen*/) +{ +} + +void KisCanvasWidgetPainter::drawLineSegments(const QPointArray& /*pointArray*/, int /*index*/, int /*nlines*/) +{ +} + +void KisCanvasWidgetPainter::drawPolyline(const QPointArray& /*pointArray*/, int /*index*/, int /*npoints*/) +{ +} + +void KisCanvasWidgetPainter::drawPolygon(const QPointArray& /*pointArray*/, bool /*winding*/, int /*index*/, int /*npoints*/) +{ +} + +void KisCanvasWidgetPainter::drawConvexPolygon(const QPointArray& /*pointArray*/, int /*index*/, int /*npoints*/) +{ +} + +void KisCanvasWidgetPainter::drawCubicBezier(const QPointArray& /*pointArray*/, int /*index*/) +{ +} + +void KisCanvasWidgetPainter::drawPixmap(int /*x*/, int /*y*/, const QPixmap& /*pixmap*/, int /*sx*/, int /*sy*/, int /*sw*/, int /*sh*/) +{ +} + +void KisCanvasWidgetPainter::drawPixmap(const QPoint& /*point*/, const QPixmap& /*pixmap*/, const QRect& /*sr*/) +{ +} + +void KisCanvasWidgetPainter::drawPixmap(const QPoint& /*point*/, const QPixmap& /*pixmap*/) +{ +} + +void KisCanvasWidgetPainter::drawPixmap(const QRect& /*r*/, const QPixmap& /*pixmap*/) +{ +} + +void KisCanvasWidgetPainter::drawImage(int /*x*/, int /*y*/, const QImage& /*image*/, int /*sx*/, int /*sy*/, int /*sw*/, int /*sh*/, int /*conversionFlags*/) +{ +} + +void KisCanvasWidgetPainter::drawImage(const QPoint& /*point*/, const QImage& /*image*/, const QRect& /*sr*/, int /*conversionFlags*/) +{ +} + +void KisCanvasWidgetPainter::drawImage(const QPoint& /*point*/, const QImage& /*image*/, int /*conversion_flags*/) +{ +} + +void KisCanvasWidgetPainter::drawImage(const QRect& /*r*/, const QImage& /*image*/) +{ +} + +void KisCanvasWidgetPainter::drawTiledPixmap(int /*x*/, int /*y*/, int /*w*/, int /*h*/, const QPixmap& /*pixmap*/, int /*sx*/, int /*sy*/) +{ +} + +void KisCanvasWidgetPainter::drawTiledPixmap(const QRect& /*r*/, const QPixmap& /*pixmap*/, const QPoint& /*point*/) +{ +} + +void KisCanvasWidgetPainter::drawTiledPixmap(const QRect& /*r*/, const QPixmap& /*pixmap*/) +{ +} + +void KisCanvasWidgetPainter::fillRect(int /*x*/, int /*y*/, int /*w*/, int /*h*/, const QBrush& /*brush*/) +{ +} + +void KisCanvasWidgetPainter::fillRect(const QRect& /*r*/, const QBrush& /*brush*/) +{ +} + +void KisCanvasWidgetPainter::eraseRect(int /*x*/, int /*y*/, int /*w*/, int /*h*/) +{ +} + +void KisCanvasWidgetPainter::eraseRect(const QRect& /*r*/) +{ +} + +void KisCanvasWidgetPainter::drawText(int /*x*/, int /*y*/, const QString& /*text*/, int /*len*/, QPainter::TextDirection /*dir*/) +{ +} + +void KisCanvasWidgetPainter::drawText(const QPoint& /*point*/, const QString& /*text*/, int /*len*/, QPainter::TextDirection /*dir*/) +{ +} + +void KisCanvasWidgetPainter::drawText(int /*x*/, int /*y*/, const QString& /*text*/, int /*pos*/, int /*len*/, QPainter::TextDirection /*dir*/) +{ +} + +void KisCanvasWidgetPainter::drawText(const QPoint& /*point*/, const QString& /*text*/, int /*pos*/, int /*len*/, QPainter::TextDirection /*dir*/) +{ +} + +void KisCanvasWidgetPainter::drawText(int /*x*/, int /*y*/, int /*w*/, int /*h*/, int /*flags*/, const QString& /*text*/, int /*len*/, QRect */*br*/, QTextParag **/*intern*/) +{ +} + +void KisCanvasWidgetPainter::drawText(const QRect& /*r*/, int /*flags*/, const QString& /*text*/, int /*len*/, QRect */*br*/, QTextParag **/*intern*/) +{ +} + +void KisCanvasWidgetPainter::drawTextItem(int /*x*/, int /*y*/, const QTextItem& /*ti*/, int /*textflags*/) +{ +} + +void KisCanvasWidgetPainter::drawTextItem(const QPoint& /*p*/, const QTextItem& /*ti*/, int /*textflags*/) +{ +} + +QRect KisCanvasWidgetPainter::boundingRect(int /*x*/, int /*y*/, int /*w*/, int /*h*/, int /*flags*/, const QString& /*text*/, int /*len*/, QTextParag **/*intern*/) +{ + return QRect(); +} + +QRect KisCanvasWidgetPainter::boundingRect(const QRect& /*r*/, int /*flags*/, const QString& /*text*/, int /*len*/, QTextParag **/*intern*/) +{ + return QRect(); +} + +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 QPaintDevice *paintDevice) +{ + m_canvasWidgetPainter = new KisQPaintDeviceCanvasPainter(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 QPaintDevice *paintDevice, bool unclipped) +{ + delete m_canvasWidgetPainter; + m_canvasWidgetPainter = new KisQPaintDeviceCanvasPainter(); + 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(); + } +} + +QFontMetrics KisCanvasPainter::fontMetrics() const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->fontMetrics(); + } + return QFontMetrics(QFont()); +} + +QFontInfo KisCanvasPainter::fontInfo() const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->fontInfo(); + } + return QFontInfo(QFont()); +} + +const QFont& KisCanvasPainter::font() const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->font(); + } + return m_defaultFont; +} + +void KisCanvasPainter::setFont(const QFont& font) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->setFont(font); + } +} + +const QPen& KisCanvasPainter::pen() const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->pen(); + } + return m_defaultPen; +} + +void KisCanvasPainter::setPen(const QPen& 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 QColor& color) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->setPen(color);; + } +} + +const QBrush& KisCanvasPainter::brush() const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->brush(); + } + return m_defaultBrush; +} + +void KisCanvasPainter::setBrush(const QBrush& brush) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->setBrush(brush); + } +} + +void KisCanvasPainter::setBrush(Qt::BrushStyle brushStyle) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->setBrush(brushStyle); + } +} + +void KisCanvasPainter::setBrush(const QColor& color) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->setBrush(color); + } +} + +QPoint KisCanvasPainter::pos() const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->pos(); + } + return QPoint(); +} + +const QColor& KisCanvasPainter::backgroundColor() const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->backgroundColor(); + } + return m_defaultColor; +} + +void KisCanvasPainter::setBackgroundColor(const QColor& 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); + } +} + +Qt::RasterOp KisCanvasPainter::rasterOp() const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->rasterOp(); + } + return Qt::CopyROP; +} + +void KisCanvasPainter::setRasterOp(Qt::RasterOp rasterOp) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->setRasterOp(rasterOp); + } +} + +const QPoint& 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 QPoint& 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); + } +} + +QRect KisCanvasPainter::window() const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->window(); + } + return QRect(); +} + +void KisCanvasPainter::setWindow(const QRect& 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); + } +} + +QRect KisCanvasPainter::viewport() const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->viewport(); + } + return QRect(); +} + +void KisCanvasPainter::setViewport(const QRect& 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 QWMatrix& KisCanvasPainter::worldMatrix() const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->worldMatrix(); + } + return m_defaultWorldMatrix; +} + +void KisCanvasPainter::setWorldMatrix(const QWMatrix& 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; +} + +QPoint KisCanvasPainter::xForm(const QPoint& point) const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->xForm(point); + } + return point; +} + +QRect KisCanvasPainter::xForm(const QRect& r) const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->xForm(r); + } + return r; +} + +QPointArray KisCanvasPainter::xForm(const QPointArray& pointArray) const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->xForm(pointArray); + } + return pointArray; +} + +QPointArray KisCanvasPainter::xForm(const QPointArray& pointArray, int index, int npoints) const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->xForm(pointArray, index, npoints); + } + return pointArray; +} + +QPoint KisCanvasPainter::xFormDev(const QPoint& point) const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->xFormDev(point); + } + return point; +} + +QRect KisCanvasPainter::xFormDev(const QRect& r) const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->xFormDev(r); + } + return r; +} + +QPointArray KisCanvasPainter::xFormDev(const QPointArray& pointArray) const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->xFormDev(pointArray); + } + return pointArray; +} + +QPointArray KisCanvasPainter::xFormDev(const QPointArray& 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; +} + +QRegion KisCanvasPainter::clipRegion(QPainter::CoordinateMode mode) const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->clipRegion(mode); + } + return QRegion(); +} + +void KisCanvasPainter::setClipRect(const QRect& r, QPainter::CoordinateMode mode) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->setClipRect(r, mode); + } +} + +void KisCanvasPainter::setClipRect(int x, int y, int w, int h, QPainter::CoordinateMode mode) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->setClipRect(x, y, w, h, mode); + } +} + +void KisCanvasPainter::setClipRegion(const QRegion& rgn, QPainter::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 QPoint& point) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawPoint(point); + } +} + +void KisCanvasPainter::drawPoints(const QPointArray& 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 QPoint& 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 QPoint& 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 QPoint& start, const QPoint& 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 QRect& 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 QColor& bgColor) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawWinFocusRect(x, y, w, h, bgColor); + } +} + +void KisCanvasPainter::drawWinFocusRect(const QRect& r) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawWinFocusRect(r); + } +} + +void KisCanvasPainter::drawWinFocusRect(const QRect& r, const QColor& 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 QRect& 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 QRect& 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 QRect& 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 QRect& 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 QRect& r, int a, int alen) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawChord(r, a, alen); + } +} + +void KisCanvasPainter::drawLineSegments(const QPointArray& pointArray, int index, int nlines) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawLineSegments(pointArray, index, nlines); + } +} + +void KisCanvasPainter::drawPolyline(const QPointArray& pointArray, int index, int npoints) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawPolyline(pointArray, index, npoints); + } +} + +void KisCanvasPainter::drawPolygon(const QPointArray& pointArray, bool winding, int index, int npoints) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawPolygon(pointArray, winding, index, npoints); + } +} + +void KisCanvasPainter::drawConvexPolygon(const QPointArray& pointArray, int index, int npoints) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawConvexPolygon(pointArray, index, npoints); + } +} + +void KisCanvasPainter::drawCubicBezier(const QPointArray& pointArray, int index) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawCubicBezier(pointArray, index); + } +} + +void KisCanvasPainter::drawPixmap(int x, int y, const QPixmap& 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 QPoint& point, const QPixmap& pixmap, const QRect& sr) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawPixmap(point, pixmap, sr); + } +} + +void KisCanvasPainter::drawPixmap(const QPoint& point, const QPixmap& pixmap) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawPixmap(point, pixmap); + } +} + +void KisCanvasPainter::drawPixmap(const QRect& r, const QPixmap& pixmap) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawPixmap(r, pixmap); + } +} + +void KisCanvasPainter::drawImage(int x, int y, const QImage& 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 QPoint& point, const QImage& image, const QRect& sr, int conversionFlags) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawImage(point, image, sr, conversionFlags); + } +} + +void KisCanvasPainter::drawImage(const QPoint& point, const QImage& image, int conversion_flags) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawImage(point, image, conversion_flags); + } +} + +void KisCanvasPainter::drawImage(const QRect& r, const QImage& image) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawImage(r, image); + } +} + +void KisCanvasPainter::drawTiledPixmap(int x, int y, int w, int h, const QPixmap& pixmap, int sx, int sy) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawTiledPixmap(x, y, w, h, pixmap, sx, sy); + } +} + +void KisCanvasPainter::drawTiledPixmap(const QRect& r, const QPixmap& pixmap, const QPoint& point) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawTiledPixmap(r, pixmap, point); + } +} + +void KisCanvasPainter::drawTiledPixmap(const QRect& r, const QPixmap& pixmap) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawTiledPixmap(r, pixmap); + } +} + +void KisCanvasPainter::fillRect(int x, int y, int w, int h, const QBrush& brush) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->fillRect(x, y, w, h, brush); + } +} + +void KisCanvasPainter::fillRect(const QRect& r, const QBrush& 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 QRect& r) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->eraseRect(r); + } +} + +void KisCanvasPainter::drawText(int x, int y, const QString& text, int len, QPainter::TextDirection dir) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawText(x, y, text, len, dir); + } +} + +void KisCanvasPainter::drawText(const QPoint& point, const QString& text, int len, QPainter::TextDirection dir) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawText(point, text, len, dir); + } +} + +void KisCanvasPainter::drawText(int x, int y, const QString& text, int pos, int len, QPainter::TextDirection dir) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawText(x, y, text, pos, len, dir); + } +} + +void KisCanvasPainter::drawText(const QPoint& point, const QString& text, int pos, int len, QPainter::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 QString& text, int len, QRect *br, QTextParag **intern) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawText(x, y, w, h, flags, text, len, br, intern); + } +} + +void KisCanvasPainter::drawText(const QRect& r, int flags, const QString& text, int len, QRect *br, QTextParag **intern) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawText(r, flags, text, len, br, intern); + } +} + +void KisCanvasPainter::drawTextItem(int x, int y, const QTextItem& ti, int textflags) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawTextItem(x, y, ti, textflags); + } +} + +void KisCanvasPainter::drawTextItem(const QPoint& p, const QTextItem& ti, int textflags) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawTextItem(p, ti, textflags); + } +} + +QRect KisCanvasPainter::boundingRect(int x, int y, int w, int h, int flags, const QString& text, int len, QTextParag **intern) +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->boundingRect(x, y, w, h, flags, text, len, intern); + } + return QRect(); +} + +QRect KisCanvasPainter::boundingRect(const QRect& r, int flags, const QString& text, int len, QTextParag **intern) +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->boundingRect(r, flags, text, len, intern); + } + return QRect(); +} + +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/krita/ui/kis_canvas_painter.h b/krita/ui/kis_canvas_painter.h new file mode 100644 index 00000000..5559057d --- /dev/null +++ b/krita/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 QFontMetrics fontMetrics() const; + virtual QFontInfo fontInfo() const; + + virtual const QFont& font() const; + virtual void setFont(const QFont&); + virtual const QPen& pen() const; + virtual void setPen(const QPen&); + virtual void setPen(Qt::PenStyle); + virtual void setPen(const QColor&); + virtual const QBrush&brush() const; + virtual void setBrush(const QBrush&); + virtual void setBrush(Qt::BrushStyle); + virtual void setBrush(const QColor&); + virtual QPoint pos() const; + + virtual const QColor&backgroundColor() const; + virtual void setBackgroundColor(const QColor&); + virtual Qt::BGMode backgroundMode() const; + virtual void setBackgroundMode(Qt::BGMode); + virtual Qt::RasterOp rasterOp() const; + virtual void setRasterOp(Qt::RasterOp); + virtual const QPoint&brushOrigin() const; + virtual void setBrushOrigin(int x, int y); + virtual void setBrushOrigin(const QPoint&); + + virtual bool hasViewXForm() const; + virtual bool hasWorldXForm() const; + + virtual void setViewXForm(bool); + virtual QRect window() const; + virtual void setWindow(const QRect&); + virtual void setWindow(int x, int y, int w, int h); + virtual QRect viewport() const; + virtual void setViewport(const QRect&); + virtual void setViewport(int x, int y, int w, int h); + + virtual void setWorldXForm(bool); + virtual const QWMatrix&worldMatrix() const; + virtual void setWorldMatrix(const QWMatrix&, 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 QPoint xForm(const QPoint&) const; + virtual QRect xForm(const QRect&) const; + virtual QPointArray xForm(const QPointArray&) const; + virtual QPointArray xForm(const QPointArray&, int index, int npoints) const; + virtual QPoint xFormDev(const QPoint&) const; + virtual QRect xFormDev(const QRect&) const; + virtual QPointArray xFormDev(const QPointArray&) const; + virtual QPointArray xFormDev(const QPointArray&, int index, int npoints) const; + + virtual void setClipping(bool); + virtual bool hasClipping() const; + virtual QRegion clipRegion(QPainter::CoordinateMode = QPainter::CoordDevice) const; + virtual void setClipRect(const QRect&, QPainter::CoordinateMode = QPainter::CoordDevice); + virtual void setClipRect(int x, int y, int w, int h, QPainter::CoordinateMode = QPainter::CoordDevice); + virtual void setClipRegion(const QRegion&, QPainter::CoordinateMode = QPainter::CoordDevice); + + virtual void drawPoint(int x, int y); + virtual void drawPoint(const QPoint&); + virtual void drawPoints(const QPointArray& a, int index=0, int npoints=-1); + virtual void moveTo(int x, int y); + virtual void moveTo(const QPoint&); + virtual void lineTo(int x, int y); + virtual void lineTo(const QPoint&); + virtual void drawLine(int x1, int y1, int x2, int y2); + virtual void drawLine(const QPoint&, const QPoint&); + virtual void drawRect(int x, int y, int w, int h); + virtual void drawRect(const QRect&); + virtual void drawWinFocusRect(int x, int y, int w, int h); + virtual void drawWinFocusRect(int x, int y, int w, int h, const QColor&bgColor); + virtual void drawWinFocusRect(const QRect&); + virtual void drawWinFocusRect(const QRect&, const QColor&bgColor); + virtual void drawRoundRect(int x, int y, int w, int h, int = 25, int = 25); + virtual void drawRoundRect(const QRect&, int = 25, int = 25); + virtual void drawEllipse(int x, int y, int w, int h); + virtual void drawEllipse(const QRect&); + virtual void drawArc(int x, int y, int w, int h, int a, int alen); + virtual void drawArc(const QRect&, int a, int alen); + virtual void drawPie(int x, int y, int w, int h, int a, int alen); + virtual void drawPie(const QRect&, int a, int alen); + virtual void drawChord(int x, int y, int w, int h, int a, int alen); + virtual void drawChord(const QRect&, int a, int alen); + virtual void drawLineSegments(const QPointArray&, int index=0, int nlines=-1); + virtual void drawPolyline(const QPointArray&, int index=0, int npoints=-1); + virtual void drawPolygon(const QPointArray&, bool winding=FALSE, int index=0, int npoints=-1); + virtual void drawConvexPolygon(const QPointArray&, int index=0, int npoints=-1); + virtual void drawCubicBezier(const QPointArray&, int index=0); + virtual void drawPixmap(int x, int y, const QPixmap&, int sx=0, int sy=0, int sw=-1, int sh=-1); + virtual void drawPixmap(const QPoint&, const QPixmap&, const QRect&sr); + virtual void drawPixmap(const QPoint&, const QPixmap&); + virtual void drawPixmap(const QRect&, const QPixmap&); + virtual void drawImage(int x, int y, const QImage&, int sx = 0, int sy = 0, int sw = -1, int sh = -1, int conversionFlags = 0); + virtual void drawImage(const QPoint&, const QImage&, const QRect&sr, int conversionFlags = 0); + virtual void drawImage(const QPoint&, const QImage&, int conversion_flags = 0); + virtual void drawImage(const QRect&, const QImage&); + virtual void drawTiledPixmap(int x, int y, int w, int h, const QPixmap&, int sx=0, int sy=0); + virtual void drawTiledPixmap(const QRect&, const QPixmap&, const QPoint&); + virtual void drawTiledPixmap(const QRect&, const QPixmap&); + //virtual void drawPicture(const QPicture&); + //virtual void drawPicture(int x, int y, const QPicture&); + //virtual void drawPicture(const QPoint&, const QPicture&); + + virtual void fillRect(int x, int y, int w, int h, const QBrush&); + virtual void fillRect(const QRect&, const QBrush&); + virtual void eraseRect(int x, int y, int w, int h); + virtual void eraseRect(const QRect&); + + virtual void drawText(int x, int y, const QString&, int len = -1, QPainter::TextDirection dir = QPainter::Auto); + virtual void drawText(const QPoint&, const QString&, int len = -1, QPainter::TextDirection dir = QPainter::Auto); + + virtual void drawText(int x, int y, const QString&, int pos, int len, QPainter::TextDirection dir = QPainter::Auto); + virtual void drawText(const QPoint&p, const QString&, int pos, int len, QPainter::TextDirection dir = QPainter::Auto); + + virtual void drawText(int x, int y, int w, int h, int flags, const QString&, int len = -1, QRect *br=0, QTextParag **intern=0); + virtual void drawText(const QRect&, int flags, const QString&, int len = -1, QRect *br=0, QTextParag **intern=0); + + virtual void drawTextItem(int x, int y, const QTextItem&ti, int textflags = 0); + virtual void drawTextItem(const QPoint& p, const QTextItem&ti, int textflags = 0); + + virtual QRect boundingRect(int x, int y, int w, int h, int flags, const QString&, int len = -1, QTextParag **intern=0); + virtual QRect boundingRect(const QRect&, int flags, const QString&, int len = -1, QTextParag **intern=0); + + virtual int tabStops() const; + virtual void setTabStops(int); + virtual int *tabArray() const; + virtual void setTabArray(int *); + +protected: + QFont m_defaultFont; + QPen m_defaultPen; + QBrush m_defaultBrush; + QColor m_defaultColor; + QPoint m_defaultBrushOrigin; + QWMatrix m_defaultWorldMatrix; +}; + +class KisCanvasPainter { +public: + KisCanvasPainter(); + KisCanvasPainter(KisCanvas *canvas); + KisCanvasPainter(const QPaintDevice *paintDevice); + + ~KisCanvasPainter(); + + bool begin(KisCanvas *canvas, bool unclipped = false); + bool begin(const QPaintDevice *paintDevice, bool unclipped = false); + + bool end(); + + void save(); + void restore(); + + QFontMetrics fontMetrics() const; + QFontInfo fontInfo() const; + + const QFont& font() const; + void setFont(const QFont&); + const QPen& pen() const; + void setPen(const QPen&); + void setPen(Qt::PenStyle); + void setPen(const QColor&); + const QBrush&brush() const; + void setBrush(const QBrush&); + void setBrush(Qt::BrushStyle); + void setBrush(const QColor&); + QPoint pos() const; + + const QColor&backgroundColor() const; + void setBackgroundColor(const QColor&); + Qt::BGMode backgroundMode() const; + void setBackgroundMode(Qt::BGMode); + Qt::RasterOp rasterOp() const; + void setRasterOp(Qt::RasterOp); + const QPoint&brushOrigin() const; + void setBrushOrigin(int x, int y); + void setBrushOrigin(const QPoint&); + + bool hasViewXForm() const; + bool hasWorldXForm() const; + + void setViewXForm(bool); + QRect window() const; + void setWindow(const QRect&); + void setWindow(int x, int y, int w, int h); + QRect viewport() const; + void setViewport(const QRect&); + void setViewport(int x, int y, int w, int h); + + void setWorldXForm(bool); + const QWMatrix&worldMatrix() const; + void setWorldMatrix(const QWMatrix&, 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; + + QPoint xForm(const QPoint&) const; + QRect xForm(const QRect&) const; + QPointArray xForm(const QPointArray&) const; + QPointArray xForm(const QPointArray&, int index, int npoints) const; + QPoint xFormDev(const QPoint&) const; + QRect xFormDev(const QRect&) const; + QPointArray xFormDev(const QPointArray&) const; + QPointArray xFormDev(const QPointArray&, int index, int npoints) const; + + void setClipping(bool); + bool hasClipping() const; + QRegion clipRegion(QPainter::CoordinateMode = QPainter::CoordDevice) const; + void setClipRect(const QRect&, QPainter::CoordinateMode = QPainter::CoordDevice); + void setClipRect(int x, int y, int w, int h, QPainter::CoordinateMode = QPainter::CoordDevice); + void setClipRegion(const QRegion&, QPainter::CoordinateMode = QPainter::CoordDevice); + + void drawPoint(int x, int y); + void drawPoint(const QPoint&); + void drawPoints(const QPointArray& a, int index=0, int npoints=-1); + void moveTo(int x, int y); + void moveTo(const QPoint&); + void lineTo(int x, int y); + void lineTo(const QPoint&); + void drawLine(int x1, int y1, int x2, int y2); + void drawLine(const QPoint&, const QPoint&); + void drawRect(int x, int y, int w, int h); + void drawRect(const QRect&); + void drawWinFocusRect(int x, int y, int w, int h); + void drawWinFocusRect(int x, int y, int w, int h, const QColor&bgColor); + void drawWinFocusRect(const QRect&); + void drawWinFocusRect(const QRect&, const QColor&bgColor); + void drawRoundRect(int x, int y, int w, int h, int = 25, int = 25); + void drawRoundRect(const QRect&, int = 25, int = 25); + void drawEllipse(int x, int y, int w, int h); + void drawEllipse(const QRect&); + void drawArc(int x, int y, int w, int h, int a, int alen); + void drawArc(const QRect&, int a, int alen); + void drawPie(int x, int y, int w, int h, int a, int alen); + void drawPie(const QRect&, int a, int alen); + void drawChord(int x, int y, int w, int h, int a, int alen); + void drawChord(const QRect&, int a, int alen); + void drawLineSegments(const QPointArray&, int index=0, int nlines=-1); + void drawPolyline(const QPointArray&, int index=0, int npoints=-1); + void drawPolygon(const QPointArray&, bool winding=FALSE, int index=0, int npoints=-1); + void drawConvexPolygon(const QPointArray&, int index=0, int npoints=-1); + void drawCubicBezier(const QPointArray&, int index=0); + void drawPixmap(int x, int y, const QPixmap&, int sx=0, int sy=0, int sw=-1, int sh=-1); + void drawPixmap(const QPoint&, const QPixmap&, const QRect&sr); + void drawPixmap(const QPoint&, const QPixmap&); + void drawPixmap(const QRect&, const QPixmap&); + void drawImage(int x, int y, const QImage&, int sx = 0, int sy = 0, int sw = -1, int sh = -1, int conversionFlags = 0); + void drawImage(const QPoint&, const QImage&, const QRect&sr, int conversionFlags = 0); + void drawImage(const QPoint&, const QImage&, int conversion_flags = 0); + void drawImage(const QRect&, const QImage&); + void drawTiledPixmap(int x, int y, int w, int h, const QPixmap&, int sx=0, int sy=0); + void drawTiledPixmap(const QRect&, const QPixmap&, const QPoint&); + void drawTiledPixmap(const QRect&, const QPixmap&); + //void drawPicture(const QPicture&); + //void drawPicture(int x, int y, const QPicture&); + //void drawPicture(const QPoint&, const QPicture&); + + void fillRect(int x, int y, int w, int h, const QBrush&); + void fillRect(const QRect&, const QBrush&); + void eraseRect(int x, int y, int w, int h); + void eraseRect(const QRect&); + + void drawText(int x, int y, const QString&, int len = -1, QPainter::TextDirection dir = QPainter::Auto); + void drawText(const QPoint&, const QString&, int len = -1, QPainter::TextDirection dir = QPainter::Auto); + + void drawText(int x, int y, const QString&, int pos, int len, QPainter::TextDirection dir = QPainter::Auto); + void drawText(const QPoint&p, const QString&, int pos, int len, QPainter::TextDirection dir = QPainter::Auto); + + void drawText(int x, int y, int w, int h, int flags, const QString&, int len = -1, QRect *br=0, QTextParag **intern=0); + void drawText(const QRect&, int flags, const QString&, int len = -1, QRect *br=0, QTextParag **intern=0); + + void drawTextItem(int x, int y, const QTextItem&ti, int textflags = 0); + void drawTextItem(const QPoint& p, const QTextItem&ti, int textflags = 0); + + QRect boundingRect(int x, int y, int w, int h, int flags, const QString&, int len = -1, QTextParag **intern=0); + QRect boundingRect(const QRect&, int flags, const QString&, int len = -1, QTextParag **intern=0); + + int tabStops() const; + void setTabStops(int); + int *tabArray() const; + void setTabArray(int *); + +protected: + KisCanvasWidgetPainter *m_canvasWidgetPainter; + QFont m_defaultFont; + QPen m_defaultPen; + QBrush m_defaultBrush; + QColor m_defaultColor; + QPoint m_defaultBrushOrigin; + QWMatrix m_defaultWorldMatrix; +}; + +#endif // KIS_CANVAS_PAINTER_H_ + diff --git a/krita/ui/kis_clipboard.cc b/krita/ui/kis_clipboard.cc new file mode 100644 index 00000000..8b6a6cd8 --- /dev/null +++ b/krita/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( QApplication::clipboard(), SIGNAL( dataChanged() ), + this, 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 + QBuffer buffer; + QCString mimeType("application/x-krita-selection"); + KoStore* store = KoStore::createStore( &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")) { + QString 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 QImage so we can interchange with other applications + QImage qimg; + KisConfig cfg; + QString monitorProfileName = cfg.monitorProfile(); + KisProfile * monitorProfile = KisMetaRegistry::instance()->csRegistry()->getProfileByName(monitorProfileName); + qimg = selection->convertToQImage(monitorProfile); + + QImageDrag *qimgDrag = new QImageDrag(qimg); + KMultipleDrag *multiDrag = new KMultipleDrag(); + if ( !qimg.isNull() ) + multiDrag->addDragObject( qimgDrag ); + KoStoreDrag* storeDrag = new KoStoreDrag( mimeType, 0 ); + storeDrag->setEncodedData( buffer.buffer() ); + multiDrag->addDragObject( storeDrag ); + + + QClipboard *cb = QApplication::clipboard(); + cb->setData(multiDrag); + m_pushedClipboard = true; +} + +KisPaintDeviceSP KisClipboard::clip() +{ + QClipboard *cb = QApplication::clipboard(); + QCString mimeType("application/x-krita-selection"); + QMimeSource *cbData = cb->data(); + + if(cbData && cbData->provides(mimeType)) + { + QBuffer buffer(cbData->encodedData(mimeType)); + KoStore* store = KoStore::createStore( &buffer, KoStore::Read, mimeType ); + KisProfile *profile=0; + + if (store->hasFile("profile.icc")) { + QByteArray data; + store->open("profile.icc"); + data = store->read(store->size()); + store->close(); + profile = new KisProfile(data); + } + + QString csName; + // ColorSpace id of layer data + if (store->hasFile("colorspace")) { + store->open("colorspace"); + csName = QString(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 + { + QImage qimg = cb->image(); + + if (qimg.isNull()) + return 0; + + KisConfig cfg; + + Q_UINT32 behaviour = cfg.pasteBehaviour(); + + if(behaviour==2) + { + // Ask user each time + behaviour = QMessageBox::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; + QString 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->convertFromQImage(qimg, profileName); + } + + return m_clip; +} + +void KisClipboard::clipboardDataChanged() +{ + if (!m_pushedClipboard) { + m_hasClip = false; + QClipboard *cb = QApplication::clipboard(); + QImage qimg = cb->image(); + QMimeSource *cbData = cb->data(); + QCString mimeType("application/x-krita-selection"); + + if(cbData && cbData->provides(mimeType)) + m_hasClip = true; + + if (!qimg.isNull()) + m_hasClip = true; + } + + m_pushedClipboard = false; +} + + +bool KisClipboard::hasClip() +{ + return m_hasClip; +} + +QSize KisClipboard::clipSize() +{ + + QClipboard *cb = QApplication::clipboard(); + QCString mimeType("application/x-krita-selection"); + QMimeSource *cbData = cb->data(); + + KisPaintDeviceSP clip; + + if(cbData && cbData->provides(mimeType)) { + + QBuffer buffer(cbData->encodedData(mimeType)); + KoStore* store = KoStore::createStore( &buffer, KoStore::Read, mimeType ); + KisProfile *profile=0; + + if (store->hasFile("profile.icc")) { + QByteArray data; + store->open("profile.icc"); + data = store->read(store->size()); + store->close(); + profile = new KisProfile(data); + } + + QString csName; + // ColorSpace id of layer data + if (store->hasFile("colorspace")) { + store->open("colorspace"); + csName = QString(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 { + QImage qimg = cb->image(); + return qimg.size(); + } +; + +} + +#include "kis_clipboard.moc" diff --git a/krita/ui/kis_clipboard.h b/krita/ui/kis_clipboard.h new file mode 100644 index 00000000..346cc742 --- /dev/null +++ b/krita/ui/kis_clipboard.h @@ -0,0 +1,79 @@ +/* + * 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 QImage; + +/** + * The Krita clipboard is a clipboard that can store paint devices + * instead of just qimage's. + */ +class KisClipboard : public QObject { + + Q_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 QImage 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(); + + QSize 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/krita/ui/kis_cmb_composite.cc b/krita/ui/kis_cmb_composite.cc new file mode 100644 index 00000000..03c846c1 --- /dev/null +++ b/krita/ui/kis_cmb_composite.cc @@ -0,0 +1,88 @@ +/* + * kis_cmb_composite.cc - part of KImageShop/Krayon/Krita + * + * 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(QWidget * parent, const char * name) + : super( false, parent, name ) +{ + connect(this, SIGNAL(activated(int)), this, SLOT(slotOpActivated(int))); + connect(this, SIGNAL(highlighted(int)), this, 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 +{ + Q_UINT32 i = super::currentItem(); + if (i > m_list.count()) return KisCompositeOp(); + + return m_list[i]; +} + +void KisCmbComposite::setCurrentItem(const KisCompositeOp& op) +{ + if (m_list.find(op) != m_list.end()) { + super::setCurrentText(op.id().name()); + } +} + +void KisCmbComposite::setCurrentText(const QString & 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 ((Q_UINT32)i > m_list.count()) return; + + emit activated(m_list[i]); +} + +void KisCmbComposite::slotOpHighlighted(int i) +{ + if ((Q_UINT32)i > m_list.count()) return; + + emit highlighted(m_list[i]); +} + + +#include "kis_cmb_composite.moc" + diff --git a/krita/ui/kis_cmb_composite.h b/krita/ui/kis_cmb_composite.h new file mode 100644 index 00000000..fa930301 --- /dev/null +++ b/krita/ui/kis_cmb_composite.h @@ -0,0 +1,70 @@ +/* + * kis_cmb_composite.h - part of KImageShop/Krayon/Krita + * + * 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 "qcombobox.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 QComboBox +{ + typedef QComboBox super; + + Q_OBJECT + + public: + + KisCmbComposite(QWidget * parent = 0, const char * name = 0 ); + virtual ~KisCmbComposite(); + + KisCompositeOp currentItem() const; + + void setCompositeOpList(const KisCompositeOpList& list); + void setCurrentItem(const KisCompositeOp& op); + void setCurrentText(const QString & 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/krita/ui/kis_cmb_idlist.cc b/krita/ui/kis_cmb_idlist.cc new file mode 100644 index 00000000..570a1ac0 --- /dev/null +++ b/krita/ui/kis_cmb_idlist.cc @@ -0,0 +1,97 @@ +/* + * kis_cmb_idlist.cc - part of KImageShop/Krayon/Krita + * + * 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(QWidget * parent, const char * name) + : super( false, parent, name ) +{ + connect(this, SIGNAL(activated(int)), this, SLOT(slotIDActivated(int))); + connect(this, SIGNAL(highlighted(int)), this, 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 +{ + Q_UINT32 i = super::currentItem(); + if (i > m_list.count()) return KisID(); + + return m_list[i]; +} + +void KisCmbIDList::setCurrent(const KisID id) +{ + if (m_list.find(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 QString & 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/krita/ui/kis_cmb_idlist.h b/krita/ui/kis_cmb_idlist.h new file mode 100644 index 00000000..287797ea --- /dev/null +++ b/krita/ui/kis_cmb_idlist.h @@ -0,0 +1,67 @@ +/* + * kis_cmb_imagetype.h - part of KImageShop/Krayon/Krita + * + * 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 "qcombobox.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 QComboBox +{ + typedef QComboBox super; + + Q_OBJECT + +public: + + KisCmbIDList(QWidget * parent = 0, const char * name = 0 ); + virtual ~KisCmbIDList(); + + +public: + void setIDList(const KisIDList & list); + void setCurrent(const KisID id); + void setCurrentText(const QString & 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/krita/ui/kis_color_cup.cc b/krita/ui/kis_color_cup.cc new file mode 100644 index 00000000..3342305f --- /dev/null +++ b/krita/ui/kis_color_cup.cc @@ -0,0 +1,118 @@ +/* + * This file is part of Krita + * + * 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(QColor c, QWidget * parent, const char * name) + : QFrame(parent, name, WType_Popup | WStyle_Customize | WStyle_NoBorder) +{ + m_color = c; + setMargin(4); + setFocusPolicy(StrongFocus); + QHBoxLayout * l = new QHBoxLayout(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(QWidget * parent, const char * name) + : QPushButton(parent, name) +{ + m_color = Qt::black; + m_popup = new KisColorPopup(m_color, this, "colorpopup"); + connect(this, SIGNAL(clicked()), this, SLOT(slotClicked())); + connect(m_popup, SIGNAL(changed( const QColor &)), this, SLOT(setColor(const QColor &))); +} + +void KisColorCup::setColor(const QColor & 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); +} + +QSize KisColorCup::sizeHint() const +{ + return style().sizeFromContents(QStyle::CT_PushButton, this, QSize(24, 24)). + expandedTo(QApplication::globalStrut()); +} + +void KisColorCup::drawButtonLabel( QPainter *painter ) +{ + int x, y, w, h; + QRect r = style().subRect( QStyle::SR_PushButtonContents, this ); + r.rect(&x, &y, &w, &h); + + int margin = 2; //style().pixelMetric( QStyle::PM_ButtonMargin, this ); + x += margin; + y += margin; + w -= 2*margin; + h -= 2*margin; + + if (isOn() || isDown()) { + x += style().pixelMetric( QStyle::PM_ButtonShiftHorizontal, this ); + y += style().pixelMetric( QStyle::PM_ButtonShiftVertical, this ); + } + + qDrawShadePanel( painter, x, y, w, h, colorGroup(), true, 1, NULL); + if ( m_color.isValid() ) + painter->fillRect( x+1, y+1, w-2, h-2, m_color ); + + if ( hasFocus() ) { + QRect focusRect = style().subRect( QStyle::SR_PushButtonFocusRect, this ); + style().drawPrimitive( QStyle::PE_FocusRect, painter, focusRect, colorGroup() ); + } + +} + +#include "kis_color_cup.moc" diff --git a/krita/ui/kis_color_cup.h b/krita/ui/kis_color_cup.h new file mode 100644 index 00000000..eb98616f --- /dev/null +++ b/krita/ui/kis_color_cup.h @@ -0,0 +1,94 @@ +/* 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 QSize; +class QPainter; +class QWidget; +class KHSSelector; +class KValueSelector; + +class KisColorPopup : public QFrame { + + Q_OBJECT + +public: + + KisColorPopup(QColor color, QWidget * w, const char * name); + virtual ~KisColorPopup() {}; + +signals: + + void changed(const QColor &); + +private: + + KHSSelector * m_khsSelector; + KValueSelector * m_valueSelector; + + QColor m_color; +}; + +class KRITAUI_EXPORT KisColorCup : public QPushButton { + + Q_OBJECT + +public: + + KisColorCup(QWidget * parent, const char * name = 0); + + virtual ~KisColorCup() {}; + + QColor color() { return m_color; }; + +signals: + + void changed(const QColor &); + +public: + + QSize sizeHint() const; + +public slots: + + void setColor(const QColor & c); + + +private slots: + + void slotClicked(); + +protected: + + virtual void drawButtonLabel( QPainter *p ); + +private: + + KisColorPopup * m_popup; + QColor m_color; +}; + +#endif diff --git a/krita/ui/kis_config.cc b/krita/ui/kis_config.cc new file mode 100644 index 00000000..b233a1eb --- /dev/null +++ b/krita/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 Q_INT32 IMG_DEFAULT_WIDTH = 512; + const Q_INT32 IMG_DEFAULT_HEIGHT = 512; + const enumCursorStyle DEFAULT_CURSOR_STYLE = CURSOR_STYLE_OUTLINE; + const Q_INT32 DEFAULT_MAX_THREADS = 4; + const Q_INT32 DEFAULT_MAX_TILES_MEM = 500; // 8192 kilobytes given 64x64 tiles with 32bpp + const Q_INT32 DEFAULT_SWAPPINESS = 100; + const Q_INT32 DEFAULT_PRESSURE_CORRECTION = 50; + const Q_INT32 DEFAULT_DOCKABILITY = 0; + const Q_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); +} + + +Q_INT32 KisConfig::defUndoLimit() const +{ + return m_cfg->readNumEntry("undolimit", DEFAULT_UNDO_LIMIT); +} + +void KisConfig::defUndoLimit(Q_INT32 limit) +{ + m_cfg->writeEntry("undolimit", limit); +} + +Q_INT32 KisConfig::defImgWidth() const +{ + return m_cfg->readNumEntry("imgWidthDef", IMG_DEFAULT_WIDTH); +} + +Q_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(Q_INT32 width) +{ + m_cfg->writeEntry("imgWidthDef", width); +} + +void KisConfig::defImgHeight(Q_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); +} + + +QString KisConfig::monitorProfile() const +{ + return m_cfg->readEntry("monitorProfile", ""); +} + +void KisConfig::setMonitorProfile(QString monitorProfile) +{ + m_cfg->writeEntry("monitorProfile", monitorProfile); +} + + +QString KisConfig::workingColorSpace() const +{ + return m_cfg->readEntry("workingColorSpace", "RGBA"); +} + +void KisConfig::setWorkingColorSpace(QString workingColorSpace) +{ + m_cfg->writeEntry(workingColorSpace, workingColorSpace); +} + + +QString KisConfig::printerColorSpace() const +{ + return m_cfg->readEntry("printerColorSpace", "CMYK"); +} + +void KisConfig::setPrinterColorSpace(QString printerColorSpace) +{ + m_cfg->writeEntry("printerColorSpace", printerColorSpace); +} + + +QString KisConfig::printerProfile() const +{ + return m_cfg->readEntry("printerProfile", ""); +} + +void KisConfig::setPrinterProfile(QString 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); +} + + +Q_INT32 KisConfig::pasteBehaviour() const +{ + return m_cfg->readNumEntry("pasteBehaviour", 2); +} + +void KisConfig::setPasteBehaviour(Q_INT32 renderIntent) +{ + m_cfg->writeEntry("pasteBehaviour", renderIntent); +} + + +Q_INT32 KisConfig::renderIntent() const +{ + return m_cfg->readNumEntry("renderIntent", INTENT_PERCEPTUAL); +} + +void KisConfig::setRenderIntent(Q_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); +} + +Q_INT32 KisConfig::maxNumberOfThreads() +{ + return m_cfg->readNumEntry("maxthreads", DEFAULT_MAX_THREADS); +} + +void KisConfig::setMaxNumberOfThreads(Q_INT32 maxThreads) +{ + m_cfg->writeEntry("maxthreads", maxThreads); +} + +Q_INT32 KisConfig::maxTilesInMem() const +{ + return m_cfg->readNumEntry("maxtilesinmem", DEFAULT_MAX_TILES_MEM); +} + +void KisConfig::setMaxTilesInMem(Q_INT32 tiles) +{ + m_cfg->writeEntry("maxtilesinmem", tiles); +} + +Q_INT32 KisConfig::swappiness() const +{ + return m_cfg->readNumEntry("swappiness", DEFAULT_SWAPPINESS); +} + +void KisConfig::setSwappiness(Q_INT32 swappiness) +{ + m_cfg->writeEntry("swappiness", swappiness); +} + +Q_INT32 KisConfig::getPressureCorrection() +{ + return m_cfg->readNumEntry( "pressurecorrection", DEFAULT_PRESSURE_CORRECTION ); +} + +void KisConfig::setPressureCorrection( Q_INT32 correction ) +{ + m_cfg->writeEntry( "pressurecorrection", correction ); +} + +Q_INT32 KisConfig::getDefaultPressureCorrection() +{ + return DEFAULT_PRESSURE_CORRECTION; +} + +bool KisConfig::tabletDeviceEnabled(const QString& tabletDeviceName) const +{ + return m_cfg->readBoolEntry("TabletDevice" + tabletDeviceName + "Enabled", false); +} + +void KisConfig::setTabletDeviceEnabled(const QString& tabletDeviceName, bool enabled) +{ + m_cfg->writeEntry("TabletDevice" + tabletDeviceName + "Enabled", enabled); +} + +Q_INT32 KisConfig::tabletDeviceAxis(const QString& tabletDeviceName, const QString& axisName, Q_INT32 defaultAxis) const +{ + return m_cfg->readNumEntry("TabletDevice" + tabletDeviceName + axisName, defaultAxis); +} + +void KisConfig::setTabletDeviceAxis(const QString& tabletDeviceName, const QString& axisName, Q_INT32 axis) const +{ + m_cfg->writeEntry("TabletDevice" + tabletDeviceName + axisName, axis); +} + +void KisConfig::setDockability( Q_INT32 dockability ) +{ + m_cfg->writeEntry( "palettesdockability", dockability ); +} + +Q_INT32 KisConfig::dockability() +{ + return m_cfg->readNumEntry("palettesdockability", DEFAULT_DOCKABILITY); +} + +Q_INT32 KisConfig::getDefaultDockability() +{ + return DEFAULT_DOCKABILITY; +} + +float KisConfig::dockerFontSize() +{ + return (float) m_cfg->readNumEntry("palettefontsize", (int)getDefaultDockerFontSize()); +} + +float KisConfig::getDefaultDockerFontSize() +{ + float ps = QMIN(9, KGlobalSettings::generalFont().pointSize() * 0.8); + if (ps < 6) ps = 6; + return ps; +} + +void KisConfig::setDockerFontSize(float size) +{ + m_cfg->writeEntry("palettefontsize", size); +} + +Q_UINT32 KisConfig::getGridMainStyle() +{ + Q_UINT32 v = m_cfg->readNumEntry("gridmainstyle", 0); + if (v > 2) + v = 2; + return v; +} + +void KisConfig::setGridMainStyle(Q_UINT32 v) +{ + m_cfg->writeEntry("gridmainstyle", v); +} + +Q_UINT32 KisConfig::getGridSubdivisionStyle() +{ + Q_UINT32 v = m_cfg->readNumEntry("gridsubdivisionstyle", 1); + if (v > 2) v = 2; + return v; +} + +void KisConfig::setGridSubdivisionStyle(Q_UINT32 v) +{ + m_cfg->writeEntry("gridsubdivisionstyle", v); +} + +QColor KisConfig::getGridMainColor() +{ + return m_cfg->readColorEntry("gridmaincolor", new QColor(99,99,99)); +} + +void KisConfig::setGridMainColor(QColor v) +{ + m_cfg->writeEntry("gridmaincolor", v); +} + +QColor KisConfig::getGridSubdivisionColor() +{ + return m_cfg->readColorEntry("gridsubdivisioncolor", new QColor(150,150,150)); +} + +void KisConfig::setGridSubdivisionColor(QColor v) +{ + m_cfg->writeEntry("gridsubdivisioncolor", v); +} + +Q_UINT32 KisConfig::getGridHSpacing() +{ + Q_INT32 v = m_cfg->readNumEntry("gridhspacing", 10); + return (Q_UINT32)QMAX(1, v ); +} + +void KisConfig::setGridHSpacing(Q_UINT32 v) +{ + m_cfg->writeEntry("gridhspacing", v); +} + +Q_UINT32 KisConfig::getGridVSpacing() +{ + Q_INT32 v = m_cfg->readNumEntry("gridvspacing", 10); + return (Q_UINT32)QMAX(1, v ); +} + +void KisConfig::setGridVSpacing(Q_UINT32 v) +{ + m_cfg->writeEntry("gridvspacing", v); +} + +Q_UINT32 KisConfig::getGridSubdivisions() +{ + Q_INT32 v = m_cfg->readNumEntry("gridsubsivisons", 2); + return (Q_UINT32)QMAX(1, v ); +} + +void KisConfig::setGridSubdivisions(Q_UINT32 v) +{ + return m_cfg->writeEntry("gridsubsivisons", v); +} + +Q_UINT32 KisConfig::getGridOffsetX() +{ + Q_INT32 v = m_cfg->readNumEntry("gridoffsetx", 0); + return (Q_UINT32)QMAX(0, v ); +} + +void KisConfig::setGridOffsetX(Q_UINT32 v) +{ + m_cfg->writeEntry("gridoffsetx", v); +} + +Q_UINT32 KisConfig::getGridOffsetY() +{ + Q_INT32 v = m_cfg->readNumEntry("gridoffsety", 0); + return (Q_UINT32)QMAX(0, v ); +} + +void KisConfig::setGridOffsetY(Q_UINT32 v) +{ + m_cfg->writeEntry("gridoffsety", v); +} + diff --git a/krita/ui/kis_config.h b/krita/ui/kis_config.h new file mode 100644 index 00000000..66824007 --- /dev/null +++ b/krita/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); + + Q_INT32 defUndoLimit() const; + void defUndoLimit(Q_INT32 limit); + + Q_INT32 defImgWidth() const; + void defImgWidth(Q_INT32 width); + + Q_INT32 defImgHeight() const; + void defImgHeight(Q_INT32 height); + + double defImgResolution() const; + void defImgResolution(double res); + + enumCursorStyle cursorStyle() const; + enumCursorStyle getDefaultCursorStyle() const; + void setCursorStyle(enumCursorStyle style); + + QString monitorProfile() const; + void setMonitorProfile(QString monitorProfile); + + QString workingColorSpace() const; + void setWorkingColorSpace(QString workingColorSpace); + + QString importProfile() const; + void setImportProfile(QString importProfile); + + QString printerColorSpace() const; + void setPrinterColorSpace(QString printerColorSpace); + + QString printerProfile() const; + void setPrinterProfile(QString printerProfile); + + bool useBlackPointCompensation() const; + void setUseBlackPointCompensation(bool useBlackPointCompensation); + + bool showRulers() const; + void setShowRulers(bool rulers); + + Q_INT32 pasteBehaviour() const; + void setPasteBehaviour(Q_INT32 behaviour); + + Q_INT32 renderIntent() const; + void setRenderIntent(Q_INT32 renderIntent); + + bool useOpenGL() const; + void setUseOpenGL(bool useOpenGL); + + bool useOpenGLShaders() const; + void setUseOpenGLShaders(bool useOpenGLShaders); + + Q_INT32 maxNumberOfThreads(); + void setMaxNumberOfThreads(Q_INT32 numberOfThreads); + + /// Maximum tiles in memory (this is a guideline, not absolute) + Q_INT32 maxTilesInMem() const; + void setMaxTilesInMem(Q_INT32 tiles); + + /// Number of tiles that will be swapped at once. The higher, the more swapped, but more + /// chance that it will become slow + Q_INT32 swappiness() const; + void setSwappiness(Q_INT32 swappiness); + + Q_INT32 getPressureCorrection(); + void setPressureCorrection( Q_INT32 correction); + Q_INT32 getDefaultPressureCorrection(); + + bool tabletDeviceEnabled(const QString& tabletDeviceName) const; + void setTabletDeviceEnabled(const QString& tabletDeviceName, bool enabled); + + Q_INT32 tabletDeviceAxis(const QString& tabletDeviceName, const QString& axisName, Q_INT32 defaultAxis) const; + void setTabletDeviceAxis(const QString& tabletDeviceName, const QString& axisName, Q_INT32 axis) const; + + Q_INT32 dockability(); + Q_INT32 getDefaultDockability(); + void setDockability( Q_INT32 dockability); + + float dockerFontSize(); + float getDefaultDockerFontSize(); + void setDockerFontSize(float); + + + Q_UINT32 getGridMainStyle(); + void setGridMainStyle(Q_UINT32 v); + Q_UINT32 getGridSubdivisionStyle(); + void setGridSubdivisionStyle(Q_UINT32 v); + QColor getGridMainColor(); + void setGridMainColor(QColor v); + QColor getGridSubdivisionColor(); + void setGridSubdivisionColor(QColor v); + Q_UINT32 getGridHSpacing(); + void setGridHSpacing(Q_UINT32 v); + Q_UINT32 getGridVSpacing(); + void setGridVSpacing(Q_UINT32 v); + Q_UINT32 getGridSubdivisions(); + void setGridSubdivisions(Q_UINT32 v); + Q_UINT32 getGridOffsetX(); + void setGridOffsetX(Q_UINT32 v); + Q_UINT32 getGridOffsetY(); + void setGridOffsetY(Q_UINT32 v); + + +private: + KisConfig(const KisConfig&); + KisConfig& operator=(const KisConfig&); + +private: + mutable KConfig *m_cfg; +}; + +#endif // KIS_CONFIG_H_ diff --git a/krita/ui/kis_controlframe.cc b/krita/ui/kis_controlframe.cc new file mode 100644 index 00000000..d2e5a432 --- /dev/null +++ b/krita/ui/kis_controlframe.cc @@ -0,0 +1,343 @@ +/* + * kis_controlframe.cc - part of Krita + * + * 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(QWidget * parent, const char* name) + : QPopupMenu(parent, name) +{ + setFocusPolicy(StrongFocus); +} + +void KisPopupFrame::keyPressEvent(QKeyEvent * e) +{ + if (e->key()== Qt::Key_Escape) + { + hide(); + e->accept(); + } + else { + e->ignore(); + } +} + + +KisControlFrame::KisControlFrame( KMainWindow * /*window*/, KisView * view, const char* name ) + : QObject(view, name) + //: KToolBar ( window, Qt::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, + 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, + view, + 0, + view->actionCollection(), + "patterns"); + + m_gradientWidget = new KisIconWidget(view, "gradients"); + m_gradientWidget->setTextLabel( i18n("Gradients") ); + action = new KWidgetAction(m_gradientWidget, + i18n("&Gradients"), + 0, + view, + 0, + view->actionCollection(), + "gradients"); + + m_paintopBox = new KisPaintopBox( view, view, "paintopbox" ); + action = new KWidgetAction(m_paintopBox, + i18n("&Painter's Tools"), + 0, + 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"); + + QHBoxLayout * l = new QHBoxLayout(m_brushChooserPopup, 2, 2, "brushpopuplayout"); + + QTabWidget * m_brushesTab = new QTabWidget(m_brushChooserPopup, "brushestab"); + m_brushesTab->setTabShape(QTabWidget::Triangular); + m_brushesTab->setFocusPolicy(QWidget::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, SIGNAL(activatedResource(KisResource*)), m_view, 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, SIGNAL(activatedResource(KisResource*)), + m_view, 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, SIGNAL(activatedResource(KisResource*)), + m_view, SLOT(brushActivated(KisResource*))); +#endif + + m_brushChooser->setFont(m_font); + m_brushMediator = new KisResourceMediator( m_brushChooser, this); + connect(m_brushMediator, SIGNAL(activatedResource(KisResource*)), m_view, 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, SIGNAL(brushChanged(KisBrush *)), this, 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"); + + QHBoxLayout * l2 = new QHBoxLayout(m_patternChooserPopup, 2, 2, "patternpopuplayout"); + + QTabWidget * m_patternsTab = new QTabWidget(m_patternChooserPopup, "patternstab"); + m_patternsTab->setTabShape(QTabWidget::Triangular); + m_patternsTab->setFocusPolicy(QWidget::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, view); + connect( m_patternMediator, SIGNAL(activatedResource(KisResource*)), view, SLOT(patternActivated(KisResource*))); + connect(customPatterns, SIGNAL(activatedResource(KisResource*)), + view, SLOT(patternActivated(KisResource*))); + + KisResourceServerBase* rServer; + rServer = KisResourceServerRegistry::instance()->get("PatternServer"); + m_patternMediator->connectServer(rServer); + + KisControlFrame::connect(view, SIGNAL(patternChanged(KisPattern *)), this, 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"); + + QHBoxLayout * l2 = new QHBoxLayout(m_gradientChooserPopup, 2, 2, "gradientpopuplayout"); + + QTabWidget * m_gradientTab = new QTabWidget(m_gradientChooserPopup, "gradientstab"); + m_gradientTab->setTabShape(QTabWidget::Triangular); + m_gradientTab->setFocusPolicy(QWidget::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, view); + connect(m_gradientMediator, SIGNAL(activatedResource(KisResource*)), view, SLOT(gradientActivated(KisResource*))); + + KisResourceServerBase* rServer; + rServer = KisResourceServerRegistry::instance()->get("GradientServer"); + m_gradientMediator->connectServer(rServer); + + connect(view, SIGNAL(gradientChanged(KisGradient *)), this, SLOT(slotGradientChanged( KisGradient *))); + m_gradientChooser->setCurrent( 0 ); + m_gradientMediator->setActiveItem( m_gradientChooser->currentItem() ); +} + + +#include "kis_controlframe.moc" + diff --git a/krita/ui/kis_controlframe.h b/krita/ui/kis_controlframe.h new file mode 100644 index 00000000..2007d5cc --- /dev/null +++ b/krita/ui/kis_controlframe.h @@ -0,0 +1,128 @@ +/* + * kis_controlframe.h - part of Krita + * + * 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 QWidget; +class QTabWidget; + +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 QPopupMenu { + + Q_OBJECT + +public: + + KisPopupFrame(QWidget * parent, const char * name = 0); + virtual void keyPressEvent(QKeyEvent *); + +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 QObject //: public KToolBar +{ + Q_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: + QFont m_font; + KisView * m_view; + + QTabWidget * m_brushesTab; + QTabWidget * 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/krita/ui/kis_cursor.cc b/krita/ui/kis_cursor.cc new file mode 100644 index 00000000..0b0b6ea5 --- /dev/null +++ b/krita/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 Qt cursors + */ +QCursor KisCursor::arrowCursor() +{ + return Qt::arrowCursor; +} + +QCursor KisCursor::upArrowCursor() +{ + return Qt::upArrowCursor; +} + +QCursor KisCursor::crossCursor() +{ + return Qt::crossCursor; +} + +QCursor KisCursor::waitCursor() +{ + return Qt::waitCursor; +} + +QCursor KisCursor::ibeamCursor() +{ + return Qt::ibeamCursor; +} + +QCursor KisCursor::sizeVerCursor() +{ + return Qt::sizeVerCursor; +} + +QCursor KisCursor::sizeHorCursor() +{ + return Qt::sizeHorCursor; +} + +QCursor KisCursor::sizeBDiagCursor() +{ + return Qt::sizeBDiagCursor; +} + +QCursor KisCursor::sizeFDiagCursor() +{ + return Qt::sizeFDiagCursor; +} + +QCursor KisCursor::sizeAllCursor() +{ + return Qt::sizeAllCursor; +} + +QCursor KisCursor::blankCursor() +{ + return Qt::blankCursor; +} + +QCursor KisCursor::splitVCursor() +{ + return Qt::splitVCursor; +} + +QCursor KisCursor::splitHCursor() +{ + return Qt::splitHCursor; +} + +QCursor KisCursor::pointingHandCursor() +{ + return Qt::pointingHandCursor; +} + + +/* + * Existing custom KimageShop cursors. Use the 'load' function for all new cursors. + */ + +QCursor 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}; + + QBitmap picker_bitmap(24, 24, picker_bits, true); + QBitmap picker_mask = picker_bitmap.createHeuristicMask( false ); + + return QCursor( picker_bitmap, picker_mask, 1, 22 ); +} + + +QCursor 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}; + + QBitmap picker_bitmap(24, 24, pickerplus_bits, true); + QBitmap picker_mask = picker_bitmap.createHeuristicMask( false ); + + return QCursor( picker_bitmap, picker_mask, 1, 22 ); +} + + +QCursor 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}; + + QBitmap picker_bitmap(24, 24, pickerminus_bits, true); + QBitmap picker_mask = picker_bitmap.createHeuristicMask( false ); + + return QCursor( picker_bitmap, picker_mask, 1, 22 ); +} + + + +QCursor 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}; + + QBitmap pen_bitmap( 24, 24, pen_bits, true ); + QBitmap pen_mask = pen_bitmap.createHeuristicMask( false ); + + return QCursor( pen_bitmap, pen_mask, 1, 22 ); +} + +QCursor 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}; + + QBitmap brush_bitmap( 25, 23, brush_bits, true ); + QBitmap brush_mask = brush_bitmap.createHeuristicMask( false ); + + return QCursor( brush_bitmap, brush_mask, 1, 21 ); +} + +QCursor 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}; + + QBitmap airbrush_bitmap( 24, 24, airbrush_bits, true ); + QBitmap airbrush_mask = airbrush_bitmap.createHeuristicMask( false ); + + return QCursor( airbrush_bitmap, airbrush_mask, 1, 22 ); +} + +QCursor 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}; + + QBitmap eraser_bitmap( 25, 24, eraser_bits, true ); + QBitmap eraser_mask = eraser_bitmap.createHeuristicMask( false ); + + return QCursor( eraser_bitmap, eraser_mask, 7, 22 ); +} + +QCursor 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}; + + QBitmap filler_bitmap( 22, 22, filler_bits, true ); + QBitmap filler_mask = filler_bitmap.createHeuristicMask( false ); + + return QCursor( filler_bitmap, filler_mask, 3, 20 ); +} + +QCursor 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}; + + QBitmap colorChanger_bitmap( 24, 23, colorChanger_bits, true ); + QBitmap colorChanger_mask = colorChanger_bitmap.createHeuristicMask( false ); + + return QCursor( colorChanger_bitmap, colorChanger_mask, 12, 10 ); +} + +QCursor 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}; + + QBitmap zoom_bitmap( 24, 23, zoom_bits, true ); + QBitmap zoom_mask = zoom_bitmap.createHeuristicMask( false ); + + return QCursor( zoom_bitmap, zoom_mask, 9, 8 ); +} + +QCursor 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}; + + QBitmap move_bitmap( 24, 24, move_bits, true ); + QBitmap move_mask = move_bitmap.createHeuristicMask( false ); + + return QCursor( move_bitmap, move_mask, 12, 11 ); +} + +QCursor KisCursor::handCursor() +{ + return KCursor::handCursor(); +} + +QCursor 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}; + + QBitmap select_bitmap(23, 23, select_bits, true); + QBitmap select_mask = select_bitmap.createHeuristicMask( false ); + + return QCursor( select_bitmap, select_mask, 11, 11 ); +} + +QCursor KisCursor::openHandCursor() +{ + return load("openhand_cursor.xpm"); +} + +QCursor KisCursor::closedHandCursor() +{ + return load("closedhand_cursor.xpm"); +} + +QCursor KisCursor::rotateCursor() +{ + return load("rotate_cursor.xpm"); +} + +QCursor KisCursor::load(const QString & iconName, int hotspotX, int hotspotY) +{ + QString filename = KisFactory::instance()->dirs()->findResource("kis_pics", iconName); + QImage cursorImage; + + cursorImage.load(filename); + Q_ASSERT(!cursorImage.isNull()); + Q_ASSERT(cursorImage.hasAlphaBuffer()); + + QBitmap bitmap(cursorImage.width(), cursorImage.height()); + QBitmap mask(cursorImage.width(), cursorImage.height()); + + QPainter bitmapPainter(&bitmap); + QPainter maskPainter(&mask); + + for (Q_INT32 x = 0; x < cursorImage.width(); ++x) { + for (Q_INT32 y = 0; y < cursorImage.height(); ++y) { + + QRgb pixel = cursorImage.pixel(x, y); + + if (qAlpha(pixel) < 128) { + bitmapPainter.setPen(Qt::color0); + maskPainter.setPen(Qt::color0); + } else { + maskPainter.setPen(Qt::color1); + + if (qGray(pixel) < 128) { + bitmapPainter.setPen(Qt::color1); + } else { + bitmapPainter.setPen(Qt::color0); + } + } + + bitmapPainter.drawPoint(x, y); + maskPainter.drawPoint(x, y); + } + } + + return QCursor(bitmap, mask, hotspotX, hotspotY); +} + diff --git a/krita/ui/kis_cursor.h b/krita/ui/kis_cursor.h new file mode 100644 index 00000000..b4e7e344 --- /dev/null +++ b/krita/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 QCursor; + +class KRITACORE_EXPORT KisCursor +{ + +public: + + KisCursor(); + + // Predefined Qt cursors. + static QCursor arrowCursor(); // standard arrow cursor + static QCursor upArrowCursor(); // upwards arrow + static QCursor crossCursor(); // crosshair + static QCursor waitCursor(); // hourglass/watch + static QCursor ibeamCursor(); // ibeam/text entry + static QCursor sizeVerCursor(); // vertical resize + static QCursor sizeHorCursor(); // horizontal resize + static QCursor sizeBDiagCursor(); // diagonal resize (/) + static QCursor sizeFDiagCursor(); // diagonal resize (\) + static QCursor sizeAllCursor(); // all directions resize + static QCursor blankCursor(); // blank/invisible cursor + static QCursor splitVCursor(); // vertical splitting + static QCursor splitHCursor(); // horziontal splitting + static QCursor pointingHandCursor(); // a pointing hand + + // Existing custom KimageShop cursors. Use the 'load' function for all new cursors. + static QCursor moveCursor(); // move tool cursor + static QCursor penCursor(); // pen tool cursor + static QCursor brushCursor(); // brush tool cursor + static QCursor airbrushCursor(); // airbrush tool cursor + static QCursor eraserCursor(); // eraser tool cursor + static QCursor fillerCursor(); // filler tool cursor + static QCursor pickerCursor(); // color picker cursor + static QCursor pickerPlusCursor(); // color picker cursor + static QCursor pickerMinusCursor(); // color picker cursor + static QCursor colorChangerCursor(); // color changer tool cursor + static QCursor selectCursor(); // select cursor + static QCursor zoomCursor(); // zoom tool cursor + static QCursor handCursor(); // hand tool cursor + static QCursor openHandCursor(); // Pan tool cursor + static QCursor closedHandCursor(); // Pan tool cursor + static QCursor 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 + // QImage can be used. + static QCursor load(const QString & imageFilename, int hotspotX = -1, int hotspotY = -1); +}; +#endif // __kis_cursor_h__ diff --git a/krita/ui/kis_custom_brush.cc b/krita/ui/kis_custom_brush.cc new file mode 100644 index 00000000..3e6046e7 --- /dev/null +++ b/krita/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(QWidget *parent, const char* name, const QString& caption, KisView* view) + : KisWdgCustomBrush(parent, name), m_view(view) +{ + Q_ASSERT(m_view); + m_mediator = 0; + setCaption(caption); + + m_brush = 0; + + preview->setScaledContents(true); + + connect(addButton, SIGNAL(pressed()), this, SLOT(slotAddPredefined())); + connect(brushButton, SIGNAL(pressed()), this, SLOT(slotUseBrush())); +// connect(exportButton, SIGNAL(pressed()), this, SLOT(slotExport())); + connect(style, SIGNAL(activated(int)), this, SLOT(slotUpdateCurrentBrush(int))); + connect(colorAsMask, SIGNAL(stateChanged(int)), this, SLOT(slotUpdateCurrentBrush(int))); +} + +KisCustomBrush::~KisCustomBrush() { + delete m_brush; +} + +void KisCustomBrush::showEvent(QShowEvent *) { + slotUpdateCurrentBrush(0); +} + +void KisCustomBrush::slotUpdateCurrentBrush(int) { + delete m_brush; + if (m_view->canvasSubject() && m_view->canvasSubject()->currentImg()) { + createBrush(); + preview->setPixmap(QPixmap(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/krita/brushes + // a unique file with this brushname + QString dir = KGlobal::dirs()->saveLocation("data", "krita/brushes"); + QString 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 + QValueVector< QValueVector > devices; + devices.push_back(QValueVector()); + 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(); + } + QValueVector 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/krita/ui/kis_custom_brush.h b/krita/ui/kis_custom_brush.h new file mode 100644 index 00000000..8beb52c2 --- /dev/null +++ b/krita/ui/kis_custom_brush.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_BRUSH_H_ +#define KIS_CUSTOM_BRUSH_H_ + +#include + +#include "wdgcustombrush.h" + + +class KisResource; +class KisView; +class KisResourceServerBase; + +class KisCustomBrush : public KisWdgCustomBrush +{ + Q_OBJECT +public: + KisCustomBrush(QWidget *parent, const char* name, const QString& caption, KisView* view); + virtual ~KisCustomBrush(); + void setResourceServer(KisResourceServerBase* server) { m_server = server; } + +public slots: + void slotUseBrush(); + +signals: + void activatedResource(KisResource *); + +protected: + virtual void showEvent(QShowEvent *); + +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/krita/ui/kis_custom_image_widget.cc b/krita/ui/kis_custom_image_widget.cc new file mode 100644 index 00000000..79b9389f --- /dev/null +++ b/krita/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(QWidget *parent, KisDoc *doc, Q_INT32 defWidth, Q_INT32 defHeight, double resolution, QString defColorSpaceName, QString imageName) + : WdgNewImage(parent) { + 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, SIGNAL(activated(const KisID &)), + this, SLOT(fillCmbProfiles(const KisID &))); + connect (m_createButton, SIGNAL( clicked() ), this, 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()); + + QColor qc(cmbColor->color()); + + m_doc->newImage(txtName->text(), (Q_INT32)intWidth->value(), (Q_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(); +} + +Q_UINT8 KisCustomImageWidget::backgroundOpacity() const +{ + Q_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; + + QValueVector profileList = KisMetaRegistry::instance()->csRegistry()->profilesFor( csf ); + QValueVector ::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/krita/ui/kis_custom_image_widget.h b/krita/ui/kis_custom_image_widget.h new file mode 100644 index 00000000..31455f85 --- /dev/null +++ b/krita/ui/kis_custom_image_widget.h @@ -0,0 +1,57 @@ +/* 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 Krita 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 +public: + /** + * Constructor. Please note that this class is being used/created by KisDoc. + * @param parent the parent widget + * @param doc the document that wants to be altered + */ + KisCustomImageWidget(QWidget *parent, KisDoc *doc, Q_INT32 defWidth, Q_INT32 defHeight, double resolution, QString defColorSpaceName, QString 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: + Q_UINT8 backgroundOpacity() const; + + KisDoc *m_doc; +}; + +#endif diff --git a/krita/ui/kis_custom_palette.cc b/krita/ui/kis_custom_palette.cc new file mode 100644 index 00000000..16631116 --- /dev/null +++ b/krita/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(QWidget *parent, const char* name, const QString& caption, KisView* view) + : KisWdgCustomPalette(parent, 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, SIGNAL(pressed()), this, SLOT(slotAddNew())); + connect(removeColor, SIGNAL(pressed()), this, SLOT(slotRemoveCurrent())); + connect(addPalette, SIGNAL(pressed()), this, 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'! + + QColor color; + int result = KColorDialog::getColor(color); + if (result != KColorDialog::Accepted) + return; + + bool ok; + QRegExpValidator validator(QRegExp(".*"), this); + QString name = KInputDialog::getText(i18n("Add Color to Palette"), + i18n("Color name (optional):"), + QString::null, &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/krita/palettes + // a unique file with this palettename + QString dir = KGlobal::dirs()->saveLocation("data", "krita/palettes"); + QString 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.") + .arg(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/krita/ui/kis_custom_palette.h b/krita/ui/kis_custom_palette.h new file mode 100644 index 00000000..1a2cfd95 --- /dev/null +++ b/krita/ui/kis_custom_palette.h @@ -0,0 +1,61 @@ +/* + * 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 +public: + KisCustomPalette(QWidget *parent, const char* name, const QString& 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/krita/ui/kis_custom_pattern.cc b/krita/ui/kis_custom_pattern.cc new file mode 100644 index 00000000..41ba73a7 --- /dev/null +++ b/krita/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(QWidget *parent, const char* name, const QString& caption, KisView* view) + : KisWdgCustomPattern(parent, name), m_view(view) +{ + Q_ASSERT(m_view); + m_mediator = 0; + setCaption(caption); + + m_pattern = 0; + + preview->setScaledContents(true); + + connect(addButton, SIGNAL(pressed()), this, SLOT(slotAddPredefined())); + connect(patternButton, SIGNAL(pressed()), this, SLOT(slotUsePattern())); + connect(exportButton, SIGNAL(pressed()), this, SLOT(slotExport())); +} + +KisCustomPattern::~KisCustomPattern() { + delete m_pattern; +} + +void KisCustomPattern::showEvent(QShowEvent *) { + slotUpdateCurrentPattern(0); +} + +void KisCustomPattern::slotUpdateCurrentPattern(int) { + delete m_pattern; + if (m_view->canvasSubject() && m_view->canvasSubject()->currentImg()) { + createPattern(); + preview->setPixmap(QPixmap(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/krita/patterns + // a unique file with this pattern name + QString dir = KGlobal::dirs()->saveLocation("data", "krita/patterns"); + QString 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/krita/ui/kis_custom_pattern.h b/krita/ui/kis_custom_pattern.h new file mode 100644 index 00000000..0e45e556 --- /dev/null +++ b/krita/ui/kis_custom_pattern.h @@ -0,0 +1,60 @@ +/* + * 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 +public: + KisCustomPattern(QWidget *parent, const char* name, const QString& caption, KisView* view); + virtual ~KisCustomPattern(); + void setResourceServer(KisResourceServerBase* server) { m_server = server; } + +signals: + void activatedResource(KisResource *); + +protected: + virtual void showEvent(QShowEvent *); + +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/krita/ui/kis_dlg_adj_layer_props.cc b/krita/ui/kis_dlg_adj_layer_props.cc new file mode 100644 index 00000000..b994ae5d --- /dev/null +++ b/krita/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 QString & layerName, + const QString & caption, + QWidget *parent, + const char *name) + : KDialogBase(parent, 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); + QWidget * page = new QWidget(this, "page widget"); + QHBoxLayout * layout = new QHBoxLayout(page, 0, 6); + setMainWidget(page); + + m_preview = new KisPreviewWidget(page, "dlgadjustment.preview"); + m_preview->slotSetDevice( dev ); + + connect( m_preview, SIGNAL(updated()), this, SLOT(refreshPreview())); + layout->addWidget(m_preview, 1, 1); + + QVBoxLayout *v1 = new QVBoxLayout( layout ); + QHBoxLayout *hl = new QHBoxLayout( v1 ); + + QLabel * lblName = new QLabel(i18n("Layer name:"), page, "lblName"); + hl->addWidget(lblName, 0, 0); + + m_layerName = new KLineEdit(page, "m_layerName"); + m_layerName->setText(layerName); + m_layerName->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); + hl->addWidget(m_layerName, 0, 1); + connect( m_layerName, SIGNAL( textChanged ( const QString & ) ), this, SLOT( slotNameChanged( const QString & ) ) ); + + 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 ) { + QLabel * labelNoConfigWidget = new QLabel( i18n("No configuration options are available for this filter"), page ); + v1->addWidget( labelNoConfigWidget ); + } + else { + v1->addWidget( m_currentConfigWidget ); + connect(m_currentConfigWidget, SIGNAL(sigPleaseUpdatePreview()), this, SLOT(slotConfigChanged())); + } + + refreshPreview(); + enableButtonOK( !m_layerName->text().isEmpty() ); +} + +void KisDlgAdjLayerProps::slotNameChanged( const QString & text ) +{ + enableButtonOK( !text.isEmpty() ); +} + +KisFilterConfiguration * KisDlgAdjLayerProps::filterConfiguration() const +{ + return m_currentFilter->configuration(m_currentConfigWidget); +} + +QString 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/krita/ui/kis_dlg_adj_layer_props.h b/krita/ui/kis_dlg_adj_layer_props.h new file mode 100644 index 00000000..783e65e5 --- /dev/null +++ b/krita/ui/kis_dlg_adj_layer_props.h @@ -0,0 +1,80 @@ +/* + * 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 QIconViewItem; +class QLabel; +class QHBoxLayout; +class KisPreviewWidget; +class KisFiltersListView; +class KisFilterConfiguration; +class KisImage; +class QGroupBox; + +/** + * Create a new adjustment layer. + */ +class KisDlgAdjLayerProps : public KDialogBase +{ + + Q_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 parent the widget parent of this dialog + * @param name the QObject name, if any + */ + KisDlgAdjLayerProps(KisAdjustmentLayerSP layer, + const QString & layerName, + const QString & caption, + QWidget *parent = 0, + const char *name = 0); + + KisFilterConfiguration * filterConfiguration() const; + QString layerName() const; + +protected slots: + + void slotNameChanged( const QString & ); + 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/krita/ui/kis_dlg_adjustment_layer.cc b/krita/ui/kis_dlg_adjustment_layer.cc new file mode 100644 index 00000000..407340ac --- /dev/null +++ b/krita/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 QString & /*layerName*/, + const QString & caption, + QWidget *parent, + const char *name) + : KDialogBase(parent, 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); + QWidget * page = new QWidget(this, "page widget"); + QGridLayout * grid = new QGridLayout(page, 3, 2, 0, 6); + setMainWidget(page); + + QLabel * lblName = new QLabel(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, SIGNAL( textChanged ( const QString & ) ), this, SLOT( slotNameChanged( const QString & ) ) ); + + m_filtersList = new KisFiltersListView(m_dev, page, true, "dlgadjustment.filtersList"); + connect(m_filtersList , SIGNAL(selectionChanged(QIconViewItem*)), this, SLOT(selectionHasChanged(QIconViewItem* ))); + grid->addMultiCellWidget(m_filtersList, 1, 2, 0, 0); + + m_preview = new KisPreviewWidget(page, "dlgadjustment.preview"); + m_preview->slotSetDevice( m_dev ); + + connect( m_preview, SIGNAL(updated()), this, SLOT(refreshPreview())); + grid->addWidget(m_preview, 1, 1); + + m_configWidgetHolder = new QGroupBox(i18n("Configuration"), page, "currentConfigWidget"); + m_configWidgetHolder->setColumnLayout(0, Qt::Horizontal); + grid->addWidget(m_configWidgetHolder, 2, 1); + + m_labelNoConfigWidget = new QLabel(i18n("No configuration options are available for this filter"), + m_configWidgetHolder); + m_configWidgetHolder->layout()->add(m_labelNoConfigWidget); + m_labelNoConfigWidget->hide(); + + resize( QSize(600, 480).expandedTo(minimumSizeHint()) ); + + m_currentConfigWidget = 0; + + enableButtonOK(0); +} + +void KisDlgAdjustmentLayer::slotNameChanged( const QString & text ) +{ + if (m_freezeName) + return; + + m_customName = !text.isEmpty(); + enableButtonOK( m_currentFilter && m_customName ); +} + +KisFilterConfiguration * KisDlgAdjustmentLayer::filterConfiguration() const +{ + return m_currentFilter->configuration(m_currentConfigWidget); +} + +QString 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 ( QIconViewItem * item ) +{ + KisFiltersIconViewItem* kisitem = (KisFiltersIconViewItem*) item; + + m_currentFilter = kisitem->filter(); + + if ( m_currentConfigWidget != 0 ) + { + m_configWidgetHolder->layout()->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->layout()->add(m_currentConfigWidget); + m_currentConfigWidget->show(); + connect(m_currentConfigWidget, SIGNAL(sigPleaseUpdatePreview()), this, 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/krita/ui/kis_dlg_adjustment_layer.h b/krita/ui/kis_dlg_adjustment_layer.h new file mode 100644 index 00000000..93b32fda --- /dev/null +++ b/krita/ui/kis_dlg_adjustment_layer.h @@ -0,0 +1,85 @@ +/* + * 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 QIconViewItem; +class QLabel; +class QHBoxLayout; +class KisPreviewWidget; +class KisFiltersListView; +class KisFilterConfiguration; +class KisImage; +class QGroupBox; + +/** + * Create a new adjustment layer. + */ +class KisDlgAdjustmentLayer : public KDialogBase +{ + + Q_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 parent the widget parent of this dialog + * @param name the QObject name, if any + */ + KisDlgAdjustmentLayer(KisImage * img, + const QString & layerName, + const QString & caption, + QWidget *parent = 0, + const char *name = 0); + + KisFilterConfiguration * filterConfiguration() const; + QString layerName() const; + +protected slots: + + void slotNameChanged( const QString & ); + void slotConfigChanged(); + void refreshPreview(); + void selectionHasChanged ( QIconViewItem * item ); + +private: + KisImage * m_image; + KisPaintDeviceSP m_dev; + KisFiltersListView * m_filtersList; + KisPreviewWidget * m_preview; + QGroupBox * m_configWidgetHolder; + QWidget * m_currentConfigWidget; + KisFilter* m_currentFilter; + KLineEdit * m_layerName; + QLabel* m_labelNoConfigWidget; + bool m_customName; + bool m_freezeName; +}; + +#endif diff --git a/krita/ui/kis_dlg_apply_profile.cc b/krita/ui/kis_dlg_apply_profile.cc new file mode 100644 index 00000000..5240a47d --- /dev/null +++ b/krita/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(QWidget *parent, const char *name) + : super(parent, name, true, "", Ok | Cancel) +{ + + setCaption(i18n("Apply Image Profile to Clipboard Data")); + m_page = new WdgApplyProfile(this); + + setMainWidget(m_page); + resize(m_page->sizeHint()); + + // 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 +{ + QString 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; + + QValueVector profileList = KisMetaRegistry::instance()->csRegistry()->profilesFor( csf ); + QValueVector ::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/krita/ui/kis_dlg_apply_profile.h b/krita/ui/kis_dlg_apply_profile.h new file mode 100644 index 00000000..2e956629 --- /dev/null +++ b/krita/ui/kis_dlg_apply_profile.h @@ -0,0 +1,48 @@ +/* + * 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 + +public: + KisDlgApplyProfile(QWidget *parent = 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/krita/ui/kis_dlg_image_properties.cc b/krita/ui/kis_dlg_image_properties.cc new file mode 100644 index 00000000..871fd9d6 --- /dev/null +++ b/krita/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, QWidget *parent, const char *name) + : super(parent, 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->sizeHint()); + + 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.find(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, SIGNAL(activated(const KisID &)), + this, 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(); +} + +QString KisDlgImageProperties::imageName() +{ + return m_page->txtName->text(); +} + +double KisDlgImageProperties::resolution() +{ + return m_page->doubleResolution->value(); +} + +QString 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() +{ + QValueVector profileList = KisMetaRegistry::instance()->csRegistry()->profilesFor( m_image->colorSpace()->id() ); + Q_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(); + QValueVector profileList = KisMetaRegistry::instance()->csRegistry()->profilesFor( csf ); + QValueVector ::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/krita/ui/kis_dlg_image_properties.h b/krita/ui/kis_dlg_image_properties.h new file mode 100644 index 00000000..2a4b84c9 --- /dev/null +++ b/krita/ui/kis_dlg_image_properties.h @@ -0,0 +1,61 @@ +/* + * 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 QButtonGroup; +class KisID; + +class KisDlgImageProperties : public KDialogBase { + typedef KDialogBase super; + Q_OBJECT + +public: + KisDlgImageProperties(KisImageSP image, + QWidget *parent = 0, + const char *name = 0); + virtual ~KisDlgImageProperties(); + + int imageWidth(); + int imageHeight(); + int opacity(); + QString imageName(); + double resolution(); + QString 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/krita/ui/kis_dlg_layer_properties.cc b/krita/ui/kis_dlg_layer_properties.cc new file mode 100644 index 00000000..442d2da1 --- /dev/null +++ b/krita/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 QString& deviceName, + Q_INT32 opacity, + const KisCompositeOp& compositeOp, + const KisColorSpace * colorSpace, + QWidget *parent, const char *name, WFlags f) + : super(parent, name, f, name, Ok | Cancel) +{ + m_page = new WdgLayerProperties(this); + m_page->layout()->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, SIGNAL( textChanged ( const QString & ) ), this, SLOT( slotNameChanged( const QString & ) ) ); + + m_page->cmbColorSpaces->setCurrent(colorSpace->id()); + m_page->cmbColorSpaces->setEnabled(false); + + QString 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 QString &_text ) +{ + enableButtonOK( !_text.isEmpty() ); +} + +QString KisDlgLayerProperties::getName() const +{ + return m_page->editName->text(); +} + +int KisDlgLayerProperties::getOpacity() const +{ + Q_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/krita/ui/kis_dlg_layer_properties.h b/krita/ui/kis_dlg_layer_properties.h new file mode 100644 index 00000000..2dc823ce --- /dev/null +++ b/krita/ui/kis_dlg_layer_properties.h @@ -0,0 +1,53 @@ +/* + * 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 QWidget; +class WdgLayerProperties; +class KisCompositeOp; +class KisColorSpace; + +class KisDlgLayerProperties : public KDialogBase { + typedef KDialogBase super; + Q_OBJECT + +public: + KisDlgLayerProperties(const QString& deviceName, + Q_INT32 opacity, + const KisCompositeOp& compositeOp, + const KisColorSpace * colorSpace, + QWidget *parent = 0, const char *name = 0, WFlags f = 0); + + virtual ~KisDlgLayerProperties(); + + QString getName() const; + Q_INT32 getOpacity() const; + KisCompositeOp getCompositeOp() const; + +protected slots: + void slotNameChanged( const QString & ); + +private: + WdgLayerProperties * m_page; +}; + +#endif // KIS_DLG_LAYER_PROPERTIES_H_ + diff --git a/krita/ui/kis_dlg_new_layer.cc b/krita/ui/kis_dlg_new_layer.cc new file mode 100644 index 00000000..3cdd58d4 --- /dev/null +++ b/krita/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 QString & profilename, + const QString & deviceName, + QWidget *parent, + const char *name) + : super(parent, name, true, "", Ok | Cancel) +{ + m_page = new WdgLayerProperties(this); + m_page->layout()->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, SIGNAL(activated(const KisID &)), + this, SLOT(fillCmbProfiles(const KisID &))); + connect(m_page->cmbColorSpaces, SIGNAL(activated(const KisID &)), + this, 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, SIGNAL( textChanged ( const QString & ) ), this, SLOT( slotNameChanged( const QString & ) ) ); + + 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; + + QValueVector profileList = KisMetaRegistry::instance()->csRegistry()->profilesFor( csf ); + QValueVector ::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 +{ + Q_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(); +} + +QString NewLayerDialog::layerName() const +{ + return m_page->editName->text(); +} + +QString NewLayerDialog::profileName() const +{ + return m_page->cmbProfile-> currentText(); +} + +#include "kis_dlg_new_layer.moc" + diff --git a/krita/ui/kis_dlg_new_layer.h b/krita/ui/kis_dlg_new_layer.h new file mode 100644 index 00000000..e250185c --- /dev/null +++ b/krita/ui/kis_dlg_new_layer.h @@ -0,0 +1,60 @@ +/* + * 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 QWidget; +class KisPaintDevice; +class WdgLayerProperties; + +class NewLayerDialog : public KDialogBase { + typedef KDialogBase super; + Q_OBJECT + +public: + NewLayerDialog(const KisID colorSpace, + const QString & profilename, + const QString & deviceName, + QWidget *parent = 0, + const char *name = 0); + + QString layerName() const; + KisCompositeOp compositeOp() const; + Q_INT32 opacity() const; + KisID colorSpaceID() const; + QString 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/krita/ui/kis_dlg_preferences.cc b/krita/ui/kis_dlg_preferences.cc new file mode 100644 index 00000000..5522bcdf --- /dev/null +++ b/krita/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( QWidget *_parent, const char *_name ) + : WdgGeneralSettings( _parent, _name ) +{ + + KisConfig cfg; + + m_cmbCursorShape->setCurrentItem(cfg.cursorStyle()); + grpDockability->setButton(cfg.dockability()); + numDockerFontSize->setValue((int)cfg.dockerFontSize()); +} + +void GeneralTab::setDefault() +{ + KisConfig cfg; + + m_cmbCursorShape->setCurrentItem( cfg.getDefaultCursorStyle()); + grpDockability->setButton(cfg.getDefaultDockability()); + numDockerFontSize->setValue((int)(cfg.getDefaultDockerFontSize())); +} + +enumCursorStyle GeneralTab::cursorStyle() +{ + return (enumCursorStyle)m_cmbCursorShape->currentItem(); +} + +enumKoDockability GeneralTab::dockability() +{ + return (enumKoDockability)grpDockability->selectedId(); +} + +float GeneralTab::dockerFontSize() +{ + return (float)numDockerFontSize->value(); +} + +//--------------------------------------------------------------------------------------------------- + +ColorSettingsTab::ColorSettingsTab(QWidget *parent, const char *name ) + : QWidget(parent, name) +{ + // XXX: Make sure only profiles that fit the specified color model + // are shown in the profile combos + + QGridLayout * l = new QGridLayout( 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->contains(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, SIGNAL(activated(const KisID &)), + this, 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; + + QValueVector profileList = KisMetaRegistry::instance()->csRegistry()->profilesFor( csf ); + QValueVector ::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; + + QValueVector profileList = KisMetaRegistry::instance()->csRegistry()->profilesFor( csf ); + QValueVector ::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(QWidget *parent, const char *name ) + : WdgPerformanceSettings(parent, 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( QWidget *parent, const char *name) + : WdgTabletSettings( parent, 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, + Q_INT32 xAxis, Q_INT32 yAxis, Q_INT32 pressureAxis, + Q_INT32 xTiltAxis, Q_INT32 yTiltAxis, Q_INT32 wheelAxis, + Q_INT32 toolIDAxis, Q_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; +} + +Q_INT32 TabletSettingsTab::DeviceSettings::numAxes() const +{ + return m_tabletDevice->numAxes(); +} + +void TabletSettingsTab::DeviceSettings::setXAxis(Q_INT32 axis) +{ + m_xAxis = axis; +} + +void TabletSettingsTab::DeviceSettings::setYAxis(Q_INT32 axis) +{ + m_yAxis = axis; +} + +void TabletSettingsTab::DeviceSettings::setPressureAxis(Q_INT32 axis) +{ + m_pressureAxis = axis; +} + +void TabletSettingsTab::DeviceSettings::setXTiltAxis(Q_INT32 axis) +{ + m_xTiltAxis = axis; +} + +void TabletSettingsTab::DeviceSettings::setYTiltAxis(Q_INT32 axis) +{ + m_yTiltAxis = axis; +} + +void TabletSettingsTab::DeviceSettings::setWheelAxis(Q_INT32 axis) +{ + m_wheelAxis = axis; +} + +void TabletSettingsTab::DeviceSettings::setToolIDAxis(Q_INT32 axis) +{ + m_toolIDAxis = axis; +} + +void TabletSettingsTab::DeviceSettings::setSerialNumberAxis(Q_INT32 axis) +{ + m_serialNumberAxis = axis; +} + +Q_INT32 TabletSettingsTab::DeviceSettings::xAxis() const +{ + return m_xAxis; +} + +Q_INT32 TabletSettingsTab::DeviceSettings::yAxis() const +{ + return m_yAxis; +} + +Q_INT32 TabletSettingsTab::DeviceSettings::pressureAxis() const +{ + return m_pressureAxis; +} + +Q_INT32 TabletSettingsTab::DeviceSettings::xTiltAxis() const +{ + return m_xTiltAxis; +} + +Q_INT32 TabletSettingsTab::DeviceSettings::yTiltAxis() const +{ + return m_yTiltAxis; +} + +Q_INT32 TabletSettingsTab::DeviceSettings::wheelAxis() const +{ + return m_wheelAxis; +} + +Q_INT32 TabletSettingsTab::DeviceSettings::toolIDAxis() const +{ + return m_toolIDAxis; +} + +Q_INT32 TabletSettingsTab::DeviceSettings::serialNumberAxis() const +{ + return m_serialNumberAxis; +} + +TabletSettingsTab::TabletDeviceSettingsDialog::TabletDeviceSettingsDialog(const QString& deviceName, DeviceSettings settings, + QWidget *parent, const char *name) + : super(parent, name, true, "", Ok | Cancel) +{ + setCaption(i18n("Configure %1").arg(deviceName)); + + m_page = new WdgTabletDeviceSettings(this); + + setMainWidget(m_page); + resize(m_page->sizeHint()); + + for (Q_INT32 axis = 0; axis < settings.numAxes(); axis++) { + QString 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 Q_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, SIGNAL(activated(int)), SLOT(slotActivateDevice(int))); + connect(chkEnableTabletDevice, SIGNAL(toggled(bool)), SLOT(slotSetDeviceEnabled(bool))); + connect(btnConfigureTabletDevice, SIGNAL(clicked()), 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() == QDialog::Accepted) + { + m_deviceSettings[cbTabletDevice->currentItem()] = dialog.settings(); + } +} + +void TabletSettingsTab::applyTabletDeviceSettings() +{ + for (Q_UINT32 deviceIndex = 0; deviceIndex < m_deviceSettings.count(); ++deviceIndex) { + m_deviceSettings[deviceIndex].applySettings(); + } +} + +#else // EXTENDED_X11_TABLET_SUPPORT + +// Fix compilation. moc 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( QWidget *parent, const char *name) + : WdgDisplaySettings( parent, name ) +{ +#ifdef HAVE_GL + KisConfig cfg; + + if (!QGLFormat::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, SIGNAL(toggled(bool)), 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(QWidget* parent) : WdgGridSettingsBase(parent) +{ + KisConfig cfg; + selectMainStyle->setCurrentItem(cfg.getGridMainStyle()); + selectSubdivisionStyle->setCurrentItem(cfg.getGridSubdivisionStyle()); + +#if KDE_IS_VERSION(3,4,0) + colorMain->setDefaultColor( QColor( 99, 99, 99 ) ); + colorSubdivision->setDefaultColor( QColor( 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, SIGNAL(toggled(bool)), this, SLOT(linkSpacingToggled( bool ))); + + connect(intHSpacing, SIGNAL(valueChanged(int)),this,SLOT(spinBoxHSpacingChanged(int))); + connect(intVSpacing, SIGNAL(valueChanged(int)),this,SLOT(spinBoxVSpacingChanged(int))); + + +} + +void GridSettingsTab::setDefault() +{ + KisConfig cfg; + selectMainStyle->setCurrentItem(0); + selectSubdivisionStyle->setCurrentItem(1); + + colorMain->setColor(QColor(99,99,99)); + colorSubdivision->setColor(QColor(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( QWidget* parent, const char* name ) + : KDialogBase( IconList, i18n("Preferences"), Ok | Cancel | Help | Default /*| Apply*/, Ok, parent, name, true, true ) +{ + QVBox *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/krita/ui/kis_dlg_preferences.h b/krita/ui/kis_dlg_preferences.h new file mode 100644 index 00000000..2d79826b --- /dev/null +++ b/krita/ui/kis_dlg_preferences.h @@ -0,0 +1,270 @@ +/* + * preferencesdlg.h - part of KImageShop^WKrita + * + * 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 QLineEdit; +class QCheckBox; +class KURLRequester; +class WdgColorSettings; +class KisCmbIDList; +class KisID; + +/** + * "General"-tab for preferences dialog + */ +class GeneralTab : public WdgGeneralSettings +{ + Q_OBJECT + +public: + + GeneralTab( QWidget *parent = 0, const char *name = 0 ); + + enumCursorStyle cursorStyle(); + enumKoDockability dockability(); + float dockerFontSize(); + + void setDefault(); + +}; + +//======================= + +class ColorSettingsTab : public QWidget +{ + Q_OBJECT + +public: + + ColorSettingsTab( QWidget *parent = 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 + +public: + PerformanceTab( QWidget *parent = 0, const char *name = 0 ); + +public: + void setDefault(); +}; + +//======================= + + +/** + * Tablet settings tab for preferences dialog + */ +class TabletSettingsTab : public WdgTabletSettings +{ +Q_OBJECT + +public: + TabletSettingsTab( QWidget *parent = 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, + Q_INT32 xAxis, Q_INT32 yAxis, Q_INT32 pressureAxis, + Q_INT32 xTiltAxis, Q_INT32 yTiltAxis, Q_INT32 wheelAxis, + Q_INT32 toolIDAxis, Q_INT32 serialNumberAxis); + DeviceSettings(); + + void applySettings(); + + void setEnabled(bool enabled); + bool enabled() const; + + Q_INT32 numAxes() const; + + void setXAxis(Q_INT32 axis); + void setYAxis(Q_INT32 axis); + void setPressureAxis(Q_INT32 axis); + void setXTiltAxis(Q_INT32 axis); + void setYTiltAxis(Q_INT32 axis); + void setWheelAxis(Q_INT32 axis); + void setToolIDAxis(Q_INT32 axis); + void setSerialNumberAxis(Q_INT32 axis); + + Q_INT32 xAxis() const; + Q_INT32 yAxis() const; + Q_INT32 pressureAxis() const; + Q_INT32 xTiltAxis() const; + Q_INT32 yTiltAxis() const; + Q_INT32 wheelAxis() const; + Q_INT32 toolIDAxis() const; + Q_INT32 serialNumberAxis() const; + + private: + KisCanvasWidget::X11TabletDevice *m_tabletDevice; + + bool m_enabled; + Q_INT32 m_xAxis; + Q_INT32 m_yAxis; + Q_INT32 m_pressureAxis; + Q_INT32 m_xTiltAxis; + Q_INT32 m_yTiltAxis; + Q_INT32 m_wheelAxis; + Q_INT32 m_toolIDAxis; + Q_INT32 m_serialNumberAxis; + }; + + class TabletDeviceSettingsDialog : public KDialogBase { + typedef KDialogBase super; + + public: + TabletDeviceSettingsDialog(const QString& deviceName, + DeviceSettings settings, + QWidget *parent = 0, + const char *name = 0); + virtual ~TabletDeviceSettingsDialog(); + + DeviceSettings settings(); + + private: + WdgTabletDeviceSettings *m_page; + DeviceSettings m_settings; + }; + + void initTabletDevices(); + + QValueVector m_deviceSettings; +#endif +}; + +//======================= + + +/** + * Display settings tab for preferences dialog + */ +class DisplaySettingsTab : public WdgDisplaySettings +{ +Q_OBJECT + +public: + DisplaySettingsTab( QWidget *parent = 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 + public: + GridSettingsTab(QWidget* parent); + public: + void setDefault(); + private slots: + void linkSpacingToggled(bool); + void spinBoxHSpacingChanged(int ); + void spinBoxVSpacingChanged(int ); + private: + bool m_linkSpacing; +}; + +//======================= + + +/** + * Preferences dialog of KImageShop^WKrayon^WKrita + */ +class PreferencesDialog : public KDialogBase +{ + Q_OBJECT + +public: + + static bool editPreferences(); + + +protected: + + PreferencesDialog( QWidget *parent = 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/krita/ui/kis_doc.cc b/krita/ui/kis_doc.cc new file mode 100644 index 00000000..7ae27bde --- /dev/null +++ b/krita/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. + */ + +// Qt +#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-krita" + +/** + * 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 QString& name, + const QString& 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; + QString m_name; + QString m_oldName; + }; + +} + +KisDoc::KisDoc(QWidget *parentWidget, const char *widgetName, QObject *parent, const char *name, bool singleViewMode) : + super(parentWidget, widgetName, parent, 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( "krita_template" ); + + init(); + + if (name) + dcopObject(); +} + +KisDoc::~KisDoc() +{ + delete m_cmdHistory; + delete m_nserver; + m_undoListeners.setAutoDelete(false); + delete m_dcop; +} + +QCString 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, QWidget* parentWidget) +{ + if (!init()) + return false; + + bool ok = false; + + QString file; + KoTemplateChooseDia::DialogType dlgtype; + + if (flags != KoDocument::InitDocFileNew) { + dlgtype = KoTemplateChooseDia::Everything; + } else { + dlgtype = KoTemplateChooseDia::OnlyTemplates; + } + + KoTemplateChooseDia::ReturnType ret = + KoTemplateChooseDia::choose(KisFactory::instance(), + file, + dlgtype, + "krita_template", + parentWidget); + 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 QString& file) +{ + setUndo(false); + + KoDocument::openExistingFile(file); + + setUndo(true); +} + +void KisDoc::openTemplate(const QString& 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, SIGNAL(documentRestored()), this, SLOT(slotDocumentRestored())); + connect(m_cmdHistory, SIGNAL(commandExecuted(KCommand *)), this, 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 Krita")); + return false; + } + + m_undoListeners.setAutoDelete(false); + + return true; +} + +QDomDocument KisDoc::saveXML() +{ + QDomDocument doc = createDomDocument("DOC", CURRENT_DTD_VERSION); + QDomElement root = doc.documentElement(); + + root.setAttribute("editor", "Krita"); + root.setAttribute("depth", sizeof(Q_UINT8)); + root.setAttribute("syntaxVersion", "1"); + + root.appendChild(saveImage(doc, m_currentImage)); + + return doc; +} + +bool KisDoc::loadOasis( const QDomDocument&, KoOasisStyles&, const QDomDocument&, 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(QIODevice *, const QDomDocument& doc) +{ + QDomElement root; + QString attr; + QDomNode 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") { + QDomElement elem = node.toElement(); + if (!(img = loadImage(elem))) + return false; + m_currentImage = img; + } else { + return false; + } + } + } + + emit loadingFinished(); + return true; +} + +bool KisDoc::loadChildren(KoStore* store) { + QPtrListIterator it(children()); + for( ; it.current(); ++it ) { + if (!it.current()->loadDocument(store)) { + return false; + } + } + return true; +} + +QDomElement KisDoc::saveImage(QDomDocument& doc, KisImageSP img) +{ + QDomElement 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()); + + Q_UINT32 count=0; + KisSaveXmlVisitor visitor(doc, image, count, true); + + m_currentImage->rootLayer()->accept(visitor); + + return image; +} + +KisImageSP KisDoc::loadImage(const QDomElement& element) +{ + + KisConfig cfg; + QString attr; + QDomNode node; + QDomNode child; + KisImageSP img; + QString name; + Q_INT32 width; + Q_INT32 height; + QString description; + QString profileProductName; + double xres; + double yres; + QString 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. + // Krita 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, SIGNAL( sigImageModified() ), this, SLOT( slotImageUpdated() )); + img->setDescription(description); + img->setResolution(xres, yres); + + loadLayers(element, img, img->rootLayer().data()); + + } + + img->notifyImageLoaded(); + + return img; +} + +void KisDoc::loadLayers(const QDomElement& element, KisImageSP img, KisGroupLayerSP parent) +{ + QDomNode node = element.firstChild(); + QDomNode 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, parent, 0); + } + } + } + } + } +} + +KisLayerSP KisDoc::loadLayer(const QDomElement& 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. + QString attr; + QString name; + Q_INT32 x; + Q_INT32 y; + Q_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 > Q_UINT8_MAX) + opacity = OPACITY_OPAQUE; + + + QString 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 QDomElement& element, KisImageSP img, + QString name, Q_INT32 x, Q_INT32 y, + Q_INT32 opacity, bool visible, bool locked, KisCompositeOp compositeOp) +{ + QString attr; + KisPaintLayerSP layer; + KisColorSpace * cs; + + QString colorspacename; + QString 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()] = QString(element.attribute("filename")); + + if ((attr = element.attribute("hasmask")).isNull()) + attr = "0"; + + if (attr == "1") { + // We add a mask, but we'll fill in the actual mask later in completeLoading with the visitor + layer->createMask(); + } + + + // Load exif info + for( QDomNode node = element.firstChild(); !node.isNull(); node = node.nextSibling() ) + { + QDomElement e = node.toElement(); + if ( !e.isNull() && e.tagName() == "ExifInfo" ) + { + layer->paintDevice()->exifInfo()->load(e); + } + } + return layer.data(); +} + +KisGroupLayerSP KisDoc::loadGroupLayer(const QDomElement& element, KisImageSP img, + QString name, Q_INT32 x, Q_INT32 y, Q_INT32 opacity, bool visible, bool locked, + KisCompositeOp compositeOp) +{ + QString 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 QDomElement& element, KisImageSP img, + QString name, Q_INT32 x, Q_INT32 y, Q_INT32 opacity, bool visible, bool locked, + KisCompositeOp compositeOp) +{ + QString attr; + KisAdjustmentLayerSP layer; + QString 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()] = QString(element.attribute("filename")); + + return layer; +} + +KisPartLayerSP KisDoc::loadPartLayer(const QDomElement& element, KisImageSP img, + QString name, Q_INT32 /*x*/, Q_INT32 /*y*/, Q_INT32 opacity, + bool visible, bool locked, + KisCompositeOp compositeOp) { + KisChildDoc* child = new KisChildDoc(this); + QString filename(element.attribute("filename")); + QDomElement 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) +{ + QString uri = url().url(); + QString location; + bool external = isStoredExtern(); + Q_INT32 totalSteps = 0; + + if (!m_currentImage) return false; + + totalSteps = (m_currentImage)->nlayers(); + + + setIOSteps(totalSteps + 1); + + // Save the layers data + Q_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 krita file to do this more generally correct + // e.g. have tags or so. + KisAnnotationSP annotation = (m_currentImage)->annotation("exif"); + if (annotation) { + location = external ? QString::null : 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 ? QString::null : 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) +{ + QString uri = url().url(); + QString location; + bool external = isStoredExtern(); + Q_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 ? QString::null : uri; + location += (m_currentImage)->name() + "/annotations/exif"; + if (store->hasFile(location)) { + QByteArray data; + store->open(location); + data = store->read(store->size()); + store->close(); + (m_currentImage)->addAnnotation(new KisAnnotation("exif", "", data)); + } + // icc profile + location = external ? QString::null : uri; + location += (m_currentImage)->name() + "/annotations/icc"; + if (store->hasFile(location)) { + QByteArray data; + store->open(location); + data = store->read(store->size()); + store->close(); + (m_currentImage)->setProfile(new KisProfile(data)); + } + + IODone(); + + setModified( false ); + setUndo(true); + return true; +} + +QWidget* KisDoc::createCustomDocumentWidget(QWidget *parent) +{ + + KisConfig cfg; + + int w = cfg.defImgWidth(); + int h = cfg.defImgHeight(); + + QSize sz = KisClipboard::instance()->clipSize(); + if (sz.isValid() && sz.width() != 0 && sz.height() != 0) { + w = sz.width(); + h = sz.height(); + } + return new KisCustomImageWidget(parent, this, w, h, cfg.defImgResolution(), cfg.workingColorSpace(),"unnamed"); +} + + +KoDocument* KisDoc::hitTest(const QPoint &pos, const QWMatrix& 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 QString& oldName, const QString& newName) +{ + (m_currentImage)->setName(newName); + + if (undo()) + addCommand(new KisCommandImageMv(this, this, newName, oldName)); +} + + +KisImageSP KisDoc::newImage(const QString& name, Q_INT32 width, Q_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, SIGNAL( sigImageModified() ), this, 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(Qt::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 QString& name, Q_INT32 width, Q_INT32 height, KisColorSpace * cs, const KisColor &bgColor, const QString &imgDescription, const double imgResolution) +{ + if (!init()) + return false; + + KisConfig cfg; + + Q_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, SIGNAL( sigImageModified() ), this, 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(); + + QValueVector 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(QWidget* parent, const char *name) +{ + KisView * v = new KisView(this, this, parent, name); + Q_CHECK_PTR(v); + + return v; +} + +void KisDoc::paintContent(QPainter& painter, const QRect& rc, bool transparent, double zoomX, double zoomY) +{ + KisConfig cfg; + QString monitorProfileName = cfg.monitorProfile(); + KisProfile * profile = KisMetaRegistry::instance()->csRegistry()->getProfileByName(monitorProfileName); + painter.scale(zoomX, zoomY); + QRect 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 QRect& rect) +{ + emit docUpdated(rect); +} + +void KisDoc::beginMacro(const QString& 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. Qt 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() ); + } +} + +Q_INT32 KisDoc::undoLimit() const +{ + return m_cmdHistory->undoLimit(); +} + +void KisDoc::setUndoLimit(Q_INT32 limit) +{ + m_cmdHistory->setUndoLimit(limit); +} + +Q_INT32 KisDoc::redoLimit() const +{ + return m_cmdHistory->redoLimit(); +} + +void KisDoc::setRedoLimit(Q_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, Q_UINT32 x, Q_UINT32 y, Q_UINT32 w, Q_UINT32 h) +{ + QRect rc(x, y, w, h); + + emit docUpdated(rc); +} + +bool KisDoc::undo() const +{ + return m_undo; +} + +void KisDoc::setIOSteps(Q_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(Q_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 QRect & 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/krita/ui/kis_doc.h b/krita/ui/kis_doc.h new file mode 100644 index 00000000..5d538cd7 --- /dev/null +++ b/krita/ui/kis_doc.h @@ -0,0 +1,223 @@ +/* + * 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 QImage; +class QString; + +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 + +public: + KisDoc(QWidget *parentWidget = 0, const char *widgetName = 0, QObject* parent = 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, QWidget* parentWidget=0); + virtual bool loadOasis( const QDomDocument&, KoOasisStyles&, const QDomDocument&, KoStore* ); + virtual bool saveOasis( KoStore*, KoXmlWriter* ); + virtual bool loadChildren( KoStore* store); + virtual bool loadXML(QIODevice *, const QDomDocument& doc); + virtual QCString mimeType() const; + virtual QWidget* createCustomDocumentWidget(QWidget *parent); + virtual KoDocument* hitTest(const QPoint &pos, const QWMatrix& matrix = QWMatrix()); + + /** + * Draw the image embedded in another KOffice document + * + * XXX: Use of transparent, zoomX and zoomY is not supported + * by Krita because we appear to be doing our zooming + * elsewhere. This may affect KOffice compatibility. + */ + virtual void paintContent(QPainter& painter, const QRect& rect, bool /*transparent*/, double /*zoomX*/, double /*zoomY*/); + + virtual QDomDocument 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 QString& macroName); + virtual void endMacro(); + + +public: + + + Q_INT32 undoLimit() const; + void setUndoLimit(Q_INT32 limit); + + Q_INT32 redoLimit() const; + void setRedoLimit(Q_INT32 limit); + + /** + * Create a new image that has this document as a parent and + * replace the current image with this image. + */ + bool newImage(const QString& name, Q_INT32 width, Q_INT32 height, KisColorSpace * cs, const KisColor &bgColor, const QString &imgDescription, const double imgResolution); + + /** + * Create a new image that has this document as a parent and + * replace the current image with this image. + */ + KisImageSP newImage(const QString& name, Q_INT32 width, Q_INT32 height, KisColorSpace * colorstrategy); + + void renameImage(const QString& oldName, const QString& 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 QRect& 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 QRect& rect); + void slotDocumentRestored(); + void slotCommandExecuted(KCommand *command); + +signals: + void docUpdated(); + void docUpdated(QRect 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(QWidget *parent, const char *name); + +protected slots: + // Overide KoDocument + virtual void openExistingFile(const QString& file); + virtual void openTemplate(const QString& file); + +private slots: + void slotUpdate(KisImageSP img, Q_UINT32 x, Q_UINT32 y, Q_UINT32 w, Q_UINT32 h); + void slotIOProgress(Q_INT8 percentage); + +private: + + QDomElement saveImage(QDomDocument& doc, KisImageSP img); + KisImageSP loadImage(const QDomElement& elem); + void loadLayers(const QDomElement& element, KisImageSP img, KisGroupLayerSP parent); + KisLayerSP loadLayer(const QDomElement& elem, KisImageSP img); + KisLayerSP loadPaintLayer(const QDomElement& elem, KisImageSP img, + QString name, Q_INT32 x, Q_INT32 y, Q_INT32 opacity, bool visible, bool locked, + KisCompositeOp compositeOp); + KisGroupLayerSP loadGroupLayer(const QDomElement& elem, KisImageSP img, + QString name, Q_INT32 x, Q_INT32 y, Q_INT32 opacity, bool visible, bool locked, + KisCompositeOp compositeOp); + KisAdjustmentLayerSP loadAdjustmentLayer(const QDomElement& elem, KisImageSP img, + QString name, Q_INT32 x, Q_INT32 y, Q_INT32 opacity, bool visible, bool locked, + KisCompositeOp compositeOp); + KisPartLayerSP loadPartLayer(const QDomElement& elem, KisImageSP img, + QString name, Q_INT32 x, Q_INT32 y, Q_INT32 opacity, + bool visible, bool locked, KisCompositeOp compositeOp); + bool init(); + + void setIOSteps(Q_INT32 nsteps); + void IOCompletedStep(); + void IODone(); + +private: + + bool m_undo; + KoCommandHistory *m_cmdHistory; + QPtrList m_undoListeners; + KisImageSP m_currentImage; + DCOPObject *m_dcop; + KisNameServer *m_nserver; + KMacroCommand *m_currentMacro; + Q_INT32 m_macroNestDepth; + Q_INT32 m_conversionDepth; + int m_ioProgressTotalSteps; + int m_ioProgressBase; + QMap m_layerFilenames; // temp storage during load + +}; + +#endif // KIS_DOC_H_ + diff --git a/krita/ui/kis_doc_iface.cc b/krita/ui/kis_doc_iface.cc new file mode 100644 index 00000000..d7db6e5d --- /dev/null +++ b/krita/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 QString& oldName, const QString& newName) +{ + m_doc->renameImage(oldName,newName); +} diff --git a/krita/ui/kis_doc_iface.h b/krita/ui/kis_doc_iface.h new file mode 100644 index 00000000..204d8b77 --- /dev/null +++ b/krita/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 QString& oldName, const QString& newName); + +private: + KisDoc *m_doc; +}; + +#endif diff --git a/krita/ui/kis_double_click_event.h b/krita/ui/kis_double_click_event.h new file mode 100644 index 00000000..0d6765aa --- /dev/null +++ b/krita/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, Qt::ButtonState button, Qt::ButtonState state) : super(DoubleClickEvent, device, pos, globalPos, pressure, xTilt, yTilt, button, state) {} +}; + +#endif // KIS_DOUBLE_CLICK_EVENT_H_ + diff --git a/krita/ui/kis_double_widget.cc b/krita/ui/kis_double_widget.cc new file mode 100644 index 00000000..935df9a2 --- /dev/null +++ b/krita/ui/kis_double_widget.cc @@ -0,0 +1,147 @@ +/* + * kis_double_widget.cc - part of Krita + * + * 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(QWidget* parent, const char* name) + : super(parent, name) +{ + init(0, 1); +} + +KisDoubleWidget::KisDoubleWidget(double min, double max, QWidget* parent, const char* name) + : super(parent, 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, SIGNAL(valueChanged(double)), this, SLOT(setSliderValue(double))); + + m_slider = new QSlider(static_cast(min * 100 + 0.5), static_cast(max * 100 + 0.5), 1, 0, QSlider::Horizontal, this, "sld"); + connect(m_slider, SIGNAL(valueChanged(int)), this, SLOT(sliderValueChanged(int))); + connect(m_slider, SIGNAL(sliderPressed()), SIGNAL(sliderPressed())); + connect(m_slider, SIGNAL(sliderReleased()), SIGNAL(sliderReleased())); + + m_layout = new QHBoxLayout(this, 0, -1, "hbox layout"); + + m_layout->addWidget(m_slider); + m_layout->addSpacing(5); + m_layout->addWidget(m_spinBox); + m_layout->addItem(new QSpacerItem(5,1,QSizePolicy::Expanding, QSizePolicy::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(QSlider::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/krita/ui/kis_double_widget.h b/krita/ui/kis_double_widget.h new file mode 100644 index 00000000..bd6043e0 --- /dev/null +++ b/krita/ui/kis_double_widget.h @@ -0,0 +1,77 @@ +/* + * kis_double_widget.h - part of Krita + * + * 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 QHBoxLayout; +class KDoubleSpinBox; + +class KisDoubleWidget : public QWidget +{ + Q_OBJECT + + typedef QWidget super; +public: + KisDoubleWidget(QWidget* parent = 0, const char* name = 0); + KisDoubleWidget(double min, double max, QWidget* parent = 0, const char* name = 0); + ~KisDoubleWidget(); + + double value() const; + void setRange(double min, double max); + + void setTickmarks(QSlider::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: + QHBoxLayout* m_layout; + QSlider* m_slider; + KDoubleSpinBox *m_spinBox; +}; + +#endif // KIS_DOUBLE_WIDGET_H + diff --git a/krita/ui/kis_event.h b/krita/ui/kis_event.h new file mode 100644 index 00000000..3d4d21bc --- /dev/null +++ b/krita/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, Qt::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; } + Qt::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; + Qt::ButtonState m_state; +}; + +#endif // KIS_EVENT_H_ + diff --git a/krita/ui/kis_factory.cc b/krita/ui/kis_factory.cc new file mode 100644 index 00000000..54a08da9 --- /dev/null +++ b/krita/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( QObject* parent, const char* name ) + : KoFactory( parent, name ) +{ + s_aboutData = newKritaAboutData(); + + (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( QWidget *parentWidget, + const char *widgetName, QObject* parent, + const char* name, const char* classname, const QStringList & ) +{ + bool bWantKoDocument = ( strcmp( classname, "KoDocument" ) == 0 ); + + KisDoc *doc = new KisDoc( parentWidget, + widgetName, parent, name, !bWantKoDocument ); + Q_CHECK_PTR(doc); + + if ( !bWantKoDocument ) + doc->setReadWrite( false ); + + return doc; +} + + +KAboutData* KisFactory::aboutData() +{ + return s_aboutData; +} + +KInstance* KisFactory::instance() +{ + QString homedir = getenv("HOME"); + + if ( !s_instance ) + { + s_instance = new KInstance(s_aboutData); + Q_CHECK_PTR(s_instance); + + s_instance->dirs()->addResourceType("krita_template", KStandardDirs::kde_default("data") + "krita/templates"); + + // XXX: Are these obsolete? + s_instance->dirs()->addResourceType("kis", KStandardDirs::kde_default("data") + "krita/"); + + s_instance->dirs()->addResourceType("kis_pics", KStandardDirs::kde_default("data") + "krita/pics/"); + + s_instance->dirs()->addResourceType("kis_images", KStandardDirs::kde_default("data") + "krita/images/"); + + s_instance->dirs()->addResourceType("toolbars", KStandardDirs::kde_default("data") + "koffice/toolbar/"); + + // Create spec + + s_instance->dirs()->addResourceType("kis_brushes", KStandardDirs::kde_default("data") + "krita/brushes/"); + s_instance->dirs()->addResourceDir("kis_brushes", "/usr/share/create/brushes/gimp"); + s_instance->dirs()->addResourceDir("kis_brushes", QDir::homeDirPath() + QString("/.create/brushes/gimp")); + + s_instance->dirs()->addResourceType("kis_patterns", KStandardDirs::kde_default("data") + "krita/patterns/"); + s_instance->dirs()->addResourceDir("kis_patterns", "/usr/share/create/patterns/gimp"); + s_instance->dirs()->addResourceDir("kis_patterns", QDir::homeDirPath() + QString("/.create/patterns/gimp")); + + s_instance->dirs()->addResourceType("kis_gradients", KStandardDirs::kde_default("data") + "krita/gradients/"); + s_instance->dirs()->addResourceDir("kis_gradients", "/usr/share/create/gradients/gimp"); + s_instance->dirs()->addResourceDir("kis_gradients", QDir::homeDirPath() + QString("/.create/gradients/gimp")); + + s_instance->dirs()->addResourceType("kis_profiles", KStandardDirs::kde_default("data") + "krita/profiles/"); + s_instance->dirs()->addResourceDir("kis_profiles", "/usr/share/color/icc"); + s_instance->dirs()->addResourceDir("kis_profiles", QDir::homeDirPath() + QString("/.icc")); + s_instance->dirs()->addResourceDir("kis_profiles", QDir::homeDirPath() + QString("/.color/icc")); + + s_instance->dirs()->addResourceType("kis_palettes", KStandardDirs::kde_default("data") + "krita/palettes/"); + s_instance->dirs()->addResourceDir("kis_palettes", "/usr/share/create/swatches"); + s_instance->dirs()->addResourceDir("kis_palettes", QDir::homeDirPath() + QString("/.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/krita/ui/kis_factory.h b/krita/ui/kis_factory.h new file mode 100644 index 00000000..c89b7a92 --- /dev/null +++ b/krita/ui/kis_factory.h @@ -0,0 +1,58 @@ +/* + * 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 + +public: + KisFactory( QObject* parent = 0, const char* name = 0 ); + ~KisFactory(); + + virtual KParts::Part *createPartObject(QWidget *parentWidget = 0, + const char *widgetName = 0, + QObject *parent = 0, + const char *name = 0, + const char *classname = "KoDocument", + const QStringList &args = QStringList() ); + + static KAboutData *aboutData(); + static KInstance *instance(); + +private: + static KInstance *s_instance; + static KAboutData *s_aboutData; +}; + +#endif diff --git a/krita/ui/kis_filter_manager.cc b/krita/ui/kis_filter_manager.cc new file mode 100644 index 00000000..550805ca --- /dev/null +++ b/krita/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 "qsignalmapper.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 QSignalMapper(this); + + connect(m_filterMapper, SIGNAL(mapped(int)), this, 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; + + QString s = f->menuCategory(); + if (s == "adjust" && !m_filterActionMenus.find("adjust")) { + am = new KActionMenu(i18n("Adjust"), ac, "adjust_filters"); + m_filterActionMenus.insert("adjust", am); + } + + else if (s == "artistic" && !m_filterActionMenus.find("artistic")) { + am = new KActionMenu(i18n("Artistic"), ac, "artistic_filters"); + m_filterActionMenus.insert("artistic", am); + } + + else if (s == "blur" && !m_filterActionMenus.find("blur")) { + am = new KActionMenu(i18n("Blur"), ac, "blur_filters"); + m_filterActionMenus.insert("blur", am); + } + + else if (s == "colors" && !m_filterActionMenus.find("colors")) { + am = new KActionMenu(i18n("Colors"), ac, "color_filters"); + m_filterActionMenus.insert("colors", am); + } + + else if (s == "decor" && !m_filterActionMenus.find("decor")) { + am = new KActionMenu(i18n("Decor"), ac, "decor_filters"); + m_filterActionMenus.insert("decor", am); + } + + else if (s == "edge" && !m_filterActionMenus.find("edge")) { + am = new KActionMenu(i18n("Edge Detection"), ac, "edge_filters"); + m_filterActionMenus.insert("edge", am); + } + + else if (s == "emboss" && !m_filterActionMenus.find("emboss")) { + am = new KActionMenu(i18n("Emboss"), ac, "emboss_filters"); + m_filterActionMenus.insert("emboss", am); + } + + else if (s == "enhance" && !m_filterActionMenus.find("enhance")) { + am = new KActionMenu(i18n("Enhance"), ac, "enhance_filters"); + m_filterActionMenus.insert("enhance", am); + } + + else if (s == "map" && !m_filterActionMenus.find("map")) { + am = new KActionMenu(i18n("Map"), ac, "map_filters"); + m_filterActionMenus.insert("map", am); + } + + else if (s == "nonphotorealistic" && !m_filterActionMenus.find("nonphotorealistic")) { + am = new KActionMenu(i18n("Non-photorealistic"), ac, "nonphotorealistic_filters"); + m_filterActionMenus.insert("nonphotorealistic", am); + } + + else if (s == "other" && !m_filterActionMenus.find("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, 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, SLOT(map()), ac, + QString("krita_filter_%1").arg((*it) . id()).ascii()); + + // Add action to the right submenu + KActionMenu * m = m_filterActionMenus.find( 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; + + QApplication::setOverrideCursor( KisCursor::waitCursor() ); + + //Apply the filter + m_lastFilterConfig = m_lastFilter->configuration(m_lastWidget); + + QRect r1 = dev->extent(); + QRect r2 = img->bounds(); + + // Filters should work only on the visible part of an image. + QRect rect = r1.intersect(r2); + + if (dev->hasSelection()) { + QRect 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(); + QApplication::restoreOverrideCursor(); + + + if (m_lastFilter->cancelRequested()) { + delete m_lastFilterConfig; + if (cmd) { + cmd->unexecute(); + delete cmd; + } + return false; + + } else { + if (dev->parentLayer()) dev->parentLayer()->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. ") + .arg(m_lastFilter->id().name()) + .arg(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. ") + .arg(m_lastFilter->id().name()) + .arg(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( (QWidget*)m_lastDialog->container(), dev ); + + bool accepted = true; + + if( m_lastWidget != 0) + { + connect(m_lastWidget, SIGNAL(sigPleaseUpdatePreview()), this, SLOT(slotConfigChanged())); + + m_lastDialog->previewWidget()->slotSetDevice( dev ); + + connect(m_lastDialog->previewWidget(), SIGNAL(updated()), this, SLOT(refreshPreview())); + + QGridLayout *widgetLayout = new QGridLayout((QWidget *)m_lastDialog->container(), 1, 1); + + widgetLayout->addWidget(m_lastWidget, 0 , 0); + + m_lastDialog->container()->setMinimumSize(m_lastWidget->minimumSize()); + + refreshPreview(); + + if(m_lastDialog->exec() == QDialog::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/krita/ui/kis_filter_manager.h b/krita/ui/kis_filter_manager.h new file mode 100644 index 00000000..69c87565 --- /dev/null +++ b/krita/ui/kis_filter_manager.h @@ -0,0 +1,86 @@ +/* + * 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 "qdict.h" +#include "qobject.h" +#include "qptrlist.h" +#include "qsignalmapper.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 QObject { + + Q_OBJECT + +public: + + KisFilterManager(KisView * parent, 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; + + QPtrList 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 + QSignalMapper * m_filterMapper; + + QDict m_filterActionMenus; +}; + +#endif diff --git a/krita/ui/kis_filters_listview.cc b/krita/ui/kis_filters_listview.cc new file mode 100644 index 00000000..04039a3b --- /dev/null +++ b/krita/ui/kis_filters_listview.cc @@ -0,0 +1,250 @@ +/* + * This file is part of Krita + * + * 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 "qtimer.h" +#include "qpainter.h" +#include "qpixmap.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(QIconView * parent, KisFiltersIconViewItem * iconItem, KisFilterConfiguration * config, KisFilter * filter, KisPaintDeviceSP dev, const QRect & bounds, KisProfile * profile) + : m_parent(parent) + , 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->convertToQImage(m_profile); + + qApp->postEvent(m_parent, new KisThumbnailDoneEvent (m_iconItem, m_pixmap)); + + } +} + +QPixmap KisFiltersThumbnailThread::pixmap() +{ + return m_pixmap; +} + +void KisFiltersThumbnailThread::cancel() +{ + m_canceled = true; + m_filter->cancel(); + +} + + +// ------------------------------------------------ + +KisFiltersIconViewItem::KisFiltersIconViewItem(QIconView * parent, const QString & text, const QPixmap & icon, + KisID id, KisFilter* filter, KisFilterConfiguration* filterConfig, + KisPaintDeviceSP thumb, const QRect & bounds, KisProfile * profile) + : QIconViewItem(parent, text, icon) + , m_id(id) + , m_filter(filter) + , m_filterconfig(filterConfig) +{ + m_thread = new KisFiltersThumbnailThread(parent, this, filterConfig, filter, thumb, bounds, profile); +} + +KisFiltersIconViewItem::~KisFiltersIconViewItem() +{ + if (m_thread) m_thread->cancel(); +} + + +// ------------------------------------------------ + +KisFiltersListView::KisFiltersListView(QWidget* parent, bool filterForAdjustmentLayers, const char* name) + : KIconView(parent, name) + , m_original(0) + , m_profile(0) + , m_filterForAdjustmentLayers(filterForAdjustmentLayers) +{ + init(); +} + +KisFiltersListView::KisFiltersListView(QWidget * parent, const char * name, WFlags f, bool filterForAdjustmentLayers) + : KIconView(parent, name, f) + , m_original(0) + , m_profile(0) + , m_filterForAdjustmentLayers(filterForAdjustmentLayers) +{ + init(); +} + +KisFiltersListView::KisFiltersListView(KisLayerSP layer, QWidget* parent, bool filterForAdjustmentLayers, const char * name) + : KIconView(parent, 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, QWidget* parent, bool filterForAdjustmentLayers, const char * name) + : KIconView(parent, name) + , m_original(device) + , m_profile(0) + , m_filterForAdjustmentLayers(filterForAdjustmentLayers) +{ + buildPreview(); + init(); +} + +void KisFiltersListView::init() +{ + setCaption(i18n("Filters List")); + setItemsMovable(false); + setSelectionMode(QIconView::Single); + setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::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(findItem(filter.name())); +} + +void KisFiltersListView::buildPreview() +{ + QTime t; + if(m_original== 0) + return; + + QApplication::setOverrideCursor(KisCursor::waitCursor()); + t.start(); + m_thumb = m_original->createThumbnailDevice(150, 150); + + t.start(); + QRect bounds = m_thumb->exactBounds(); + QPixmap pm(bounds.width(), bounds.height()); + QPainter 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(); + } + } + } + QApplication::restoreOverrideCursor(); +} + + +void KisFiltersListView::customEvent(QCustomEvent * e) +{ + KisThumbnailDoneEvent * ev = dynamic_cast(e); + if (ev) { + QPixmap * p = ev->m_iconItem->pixmap(); + QImage 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; + + QPainter gc(p); + gc.drawImage(QPoint(x,y), img); + gc.end(); + + //ev->m_iconItem->setPixmap(QPixmap(*p)); + arrangeItemsInGrid(); + } +} diff --git a/krita/ui/kis_filters_listview.h b/krita/ui/kis_filters_listview.h new file mode 100644 index 00000000..7a7e5e89 --- /dev/null +++ b/krita/ui/kis_filters_listview.h @@ -0,0 +1,143 @@ +/* + * This file is part of Krita + * + * 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 QCustomEvent +{ +public: + + KisThumbnailDoneEvent(KisFiltersIconViewItem * iconItem, const QImage & img) + : QCustomEvent(QEvent::User + 1969) + , m_iconItem(iconItem) + , m_image(img) {}; + + KisFiltersIconViewItem * m_iconItem; + QImage m_image; + +}; + + +class KisFiltersThumbnailThread : public KisThread +{ +public: + + KisFiltersThumbnailThread(QIconView * parent, + KisFiltersIconViewItem * iconItem, + KisFilterConfiguration * config, KisFilter * filter, + KisPaintDeviceSP dev, const QRect & bounds, + KisProfile * profile); + + ~KisFiltersThumbnailThread(); + + virtual void run(); + QPixmap pixmap(); + void cancel(); + +private: + QIconView * m_parent; + KisFiltersIconViewItem * m_iconItem; + KisFilterConfiguration * m_config; + KisFilter * m_filter; + KisPaintDeviceSP m_dev; + const QRect m_bounds; + KisProfile * m_profile; + QImage m_pixmap; +}; + +class KisFiltersIconViewItem : public QIconViewItem { +public: + KisFiltersIconViewItem( QIconView * parent, const QString & text, const QPixmap & icon, + KisID id, KisFilter* filter, KisFilterConfiguration* filterConfig, + KisPaintDeviceSP thumb, const QRect & 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(QWidget * parent = 0, const char * name = 0, WFlags f = 0, bool filterForAdjustmentLayers = false); + KisFiltersListView(QWidget* parent, bool filterForAdjustmentLayers = false, const char* name = 0); + KisFiltersListView(KisLayerSP layer, QWidget* parent, bool filterForAdjustmentLayers = false, const char * name = 0) KDE_DEPRECATED; + KisFiltersListView(KisPaintDeviceSP layer, QWidget* parent, bool filterForAdjustmentLayers = false, const char * name = 0); + + virtual void customEvent(QCustomEvent *); + + 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/krita/ui/kis_gradient_chooser.cc b/krita/ui/kis_gradient_chooser.cc new file mode 100644 index 00000000..ca0bfeb0 --- /dev/null +++ b/krita/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, QWidget * parent, const char *name) + : KDialogBase(parent, name, false, i18n("Custom Gradient"), Close) +{ + m_page = new KisAutogradient(this, "autogradient", i18n("Custom Gradient")); + setMainWidget(m_page); + connect(m_page, SIGNAL(activatedResource(KisResource *)), view, SLOT(gradientActivated(KisResource*))); +} + +KisGradientChooser::KisGradientChooser(KisView * view, QWidget *parent, const char *name) : super(parent, name) +{ + m_lbName = new QLabel(this); + + m_customGradient = new QPushButton(i18n("Custom Gradient..."), this, "custom gradient button"); + + KisCustomGradientDialog * autogradient = new KisCustomGradientDialog(view, this, "autogradient"); + connect(m_customGradient, SIGNAL(clicked()), autogradient, SLOT(show())); + + QVBoxLayout *mainLayout = new QVBoxLayout(this, 2, -1, "main layout"); + + 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/krita/ui/kis_gradient_chooser.h b/krita/ui/kis_gradient_chooser.h new file mode 100644 index 00000000..5b6d7226 --- /dev/null +++ b/krita/ui/kis_gradient_chooser.h @@ -0,0 +1,61 @@ +/* + * 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 QLabel; +class QPushButton; +class KisView; + +class KisCustomGradientDialog : public KDialogBase { + + Q_OBJECT + +public: + + KisCustomGradientDialog(KisView * view, QWidget * parent, const char *name); + +private: + + KisAutogradient * m_page; + +}; + +class KisGradientChooser : public KisItemChooser { + typedef KisItemChooser super; + Q_OBJECT + +public: + // XXX: On library redesign, remove m_view parameter here, it's just a temporary hack for the autogradient dialog! + KisGradientChooser(KisView * view, QWidget *parent = 0, const char *name = 0); + virtual ~KisGradientChooser(); + +protected: + virtual void update(KoIconItem *item); + +private: + QLabel *m_lbName; + QPushButton * m_customGradient; +}; + +#endif // KIS_GRADIENT_CHOOSER_H_ + diff --git a/krita/ui/kis_gradient_slider_widget.cc b/krita/ui/kis_gradient_slider_widget.cc new file mode 100644 index 00000000..05e724a3 --- /dev/null +++ b/krita/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(QWidget *parent, const char* name, WFlags f ) + : QWidget( parent, 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, SIGNAL( activated(int) ), 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 ( QPaintEvent* pe ) +{ + QWidget::paintEvent( pe ); + QPixmap pixmap( width(), height() ); + pixmap.fill( colorGroup().background() ); + QPainter painter( &pixmap ); + painter.setPen( Qt::black ); + painter.drawRect( MARGIN, MARGIN, width() - 2 * MARGIN, height()- 2 * MARGIN - HANDLE_SIZE ); + if(m_autogradientResource) + { + QImage img = m_autogradientResource->generatePreview(width()- 2* MARGIN - 2, height()- 2* MARGIN - HANDLE_SIZE - 2); + QPixmap 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, QBrush( Qt::white ) ); + if( m_selectedSegment ) + { + QRect selection( qRound( m_selectedSegment->startOffset()*(double)(width()- 2 * MARGIN - 2) ) + 6, + height()- HANDLE_SIZE - MARGIN, + qRound( ( m_selectedSegment->endOffset() - m_selectedSegment->startOffset() )*(double)(width()-12) ), + HANDLE_SIZE ); + painter.fillRect( selection, QBrush( colorGroup().highlight() ) ); + } + + QPointArray triangle(3); + QValueVector handlePositions = m_autogradientResource->getHandlePositions(); + int position; + painter.setBrush( QBrush( Qt::black) ); + for (uint i = 0; i < handlePositions.count(); i++) + { + position = qRound( handlePositions[i] * (double)( width()-12) ) + 6; + triangle[0] = QPoint(position, height() - HANDLE_SIZE - MARGIN ); + triangle[1] = QPoint(position + (HANDLE_SIZE / 2 - 1), height() - MARGIN ); + triangle[2] = QPoint(position - (HANDLE_SIZE / 2 - 1), height() - MARGIN ); + painter.drawPolygon(triangle); + } + painter.setBrush( QBrush( Qt::white ) ); + QValueVector middleHandlePositions = m_autogradientResource->getMiddleHandlePositions(); + for (uint i = 0; i < middleHandlePositions.count(); i++) + { + position = qRound( middleHandlePositions[i] * (double)(width()-12) ) + 6; + triangle[0] = QPoint(position, height()-HANDLE_SIZE - MARGIN); + triangle[1] = QPoint(position + (HANDLE_SIZE / 2 - 2), height() - MARGIN); + triangle[2] = QPoint(position - (HANDLE_SIZE / 2 - 2), height() - MARGIN); + painter.drawPolygon(triangle); + } + } + bitBlt( this, 0, 0, &pixmap, 0, 0, pixmap.width(), pixmap.height(), Qt::CopyROP); +} + +void KisGradientSliderWidget::mousePressEvent( QMouseEvent * e ) +{ + QWidget::mousePressEvent( e ); + if( ( e->y() < MARGIN || e->y() > height() - MARGIN ) || ( e->x() < MARGIN || e->x() > width() - MARGIN ) || e-> button() != 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; + QRect leftHandle( qRound(m_currentSegment->startOffset() * (double)(width()-2*MARGIN-2)+ MARGIN - (HANDLE_SIZE/2 - 1 )), + height() - HANDLE_SIZE, + HANDLE_SIZE - 1, + HANDLE_SIZE); + QRect middleHandle( qRound(m_currentSegment->middleOffset() * (double)(width()-2*MARGIN-2)+ MARGIN - (HANDLE_SIZE/2 -2) ), + height() - HANDLE_SIZE - MARGIN, + HANDLE_SIZE - 1, + HANDLE_SIZE); + QRect rightHandle( qRound(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.contains( e->pos() ) ) + m_drag = LEFT_DRAG; + else if( middleHandle.contains( e->pos() ) ) + m_drag = MIDDLE_DRAG; + else if( rightHandle.contains( e->pos() ) ) + m_drag = RIGHT_DRAG; + } + else + { + if( rightHandle.contains( e->pos() ) ) + m_drag = RIGHT_DRAG; + else if( middleHandle.contains( e->pos() ) ) + m_drag = MIDDLE_DRAG; + else if( leftHandle.contains( e->pos() ) ) + m_drag = LEFT_DRAG; + } + + if( m_drag == NO_DRAG ) + { + m_selectedSegment = m_currentSegment; + emit sigSelectedSegment( m_selectedSegment ); + } + } + repaint(false); +} + +void KisGradientSliderWidget::mouseReleaseEvent ( QMouseEvent * e ) +{ + QWidget::mouseReleaseEvent( e ); + m_drag = NO_DRAG; +} + +void KisGradientSliderWidget::mouseMoveEvent( QMouseEvent * e ) +{ + QWidget::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 ); + + repaint(false); +} + +void KisGradientSliderWidget::contextMenuEvent( QContextMenuEvent * 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 ); + repaint(false); +} + +#include "kis_gradient_slider_widget.moc" diff --git a/krita/ui/kis_gradient_slider_widget.h b/krita/ui/kis_gradient_slider_widget.h new file mode 100644 index 00000000..4bc00543 --- /dev/null +++ b/krita/ui/kis_gradient_slider_widget.h @@ -0,0 +1,79 @@ +/* + * 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 QWidget +{ + Q_OBJECT + +public: + KisGradientSliderWidget(QWidget *parent = 0, const char* name = 0, WFlags f = 0); + +public: + virtual void paintEvent ( QPaintEvent * ); + void setGradientResource( KisAutogradientResource* agr); + KisGradientSegment* selectedSegment() { return m_selectedSegment; }; + +signals: + void sigSelectedSegment(KisGradientSegment*); + void sigChangedSegment(KisGradientSegment*); + +protected: + virtual void mousePressEvent( QMouseEvent * e ); + virtual void mouseReleaseEvent ( QMouseEvent * e ); + virtual void mouseMoveEvent( QMouseEvent * e ); + virtual void contextMenuEvent( QContextMenuEvent * 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/krita/ui/kis_grid_drawer.cpp b/krita/ui/kis_grid_drawer.cpp new file mode 100644 index 00000000..3af8a92e --- /dev/null +++ b/krita/ui/kis_grid_drawer.cpp @@ -0,0 +1,223 @@ +/* + * This file is part of Krita + * + * 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(Q_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 QRect& /*wr*/, const KisSubPerspectiveGrid* grid) +{ + Q_UNUSED(image); + KisConfig cfg; + QPen mainPen = QPen ( cfg.getGridMainColor(), 1, gs2style( cfg.getGridMainStyle() ) ); + QPen subdivisionPen = QPen ( 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.roundQPoint(), pol1b.roundQPoint() ); + + KisPoint pol2 = *grid->bottomRight() + i * v23; + KisPerspectiveMath::LineEquation d2 = KisPerspectiveMath::computeLineEquation( &pol2, &horizVanishingPoint ); + KisPoint pol2b = KisPerspectiveMath::computeIntersection(d2,d41); + drawLine( pol2.roundQPoint(), pol2b.roundQPoint() ); + } + 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 QRect& wr) +{ + KisConfig cfg; + + Q_UINT32 offsetx = cfg.getGridOffsetX(); + Q_UINT32 offsety = cfg.getGridOffsetY(); + Q_UINT32 hspacing = cfg.getGridHSpacing(); + Q_UINT32 vspacing = cfg.getGridVSpacing(); + Q_UINT32 subdivision = cfg.getGridSubdivisions() - 1; + //double ihspsub = hspacing / (double)subdivision; + //double ivspsub = hspacing / (double)subdivision; + + Q_INT32 imageWidth = image->width(); + Q_INT32 imageHeight = image->height(); + + // Draw vertical line + QPen mainPen = QPen ( cfg.getGridMainColor(), 1, gs2style( cfg.getGridMainStyle() ) ); + QPen subdivisionPen = QPen ( cfg.getGridSubdivisionColor(), 1, gs2style( cfg.getGridSubdivisionStyle() ) ); + Q_UINT32 i = 0; + for( Q_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( Q_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 QPen& pen) +{ +#ifdef HAVE_GL + Qt::PenStyle penStyle = pen.style(); + + if (penStyle == Qt::SolidLine) { + glDisable(GL_LINE_STIPPLE); + } else { + GLushort lineStipple; + + switch (penStyle) { + case Qt::NoPen: + lineStipple = 0; + break; + default: + case Qt::SolidLine: + lineStipple = 0xffff; + break; + case Qt::DashLine: + lineStipple = 0x3fff; + break; + case Qt::DotLine: + lineStipple = 0x3333; + break; + case Qt::DashDotLine: + lineStipple = 0x33ff; + break; + case Qt::DashDotDotLine: + lineStipple = 0x333f; + break; + } + + glEnable(GL_LINE_STIPPLE); + glLineStipple(1, lineStipple); + } + + QColor penColor = pen.color(); + + glColor3ub(penColor.red(), penColor.green(), penColor.blue()); +#else + Q_UNUSED(pen); +#endif +} + +void OpenGLGridDrawer::drawLine(Q_INT32 x1, Q_INT32 y1, Q_INT32 x2, Q_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/krita/ui/kis_grid_drawer.h b/krita/ui/kis_grid_drawer.h new file mode 100644 index 00000000..1078883e --- /dev/null +++ b/krita/ui/kis_grid_drawer.h @@ -0,0 +1,71 @@ +/* + * This file is part of Krita + * + * 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 QRect& wr); + void drawPerspectiveGrid(KisImageSP image, const QRect& wr, const KisSubPerspectiveGrid* grid); + + virtual void setPen(const QPen& pen) = 0; + virtual void drawLine(Q_INT32 x1, Q_INT32 y1, Q_INT32 x2, Q_INT32 y2) = 0; + inline void drawLine(const QPoint& p1, const QPoint& p2) { drawLine(p1.x(), p1.y(), p2.x(), p2.y() ); } + inline void drawLine(const KisPoint* p1, const KisPoint* p2) { drawLine( p1->roundQPoint(), p2->roundQPoint()); } + private: + Qt::PenStyle gs2style(Q_UINT32 s); +}; + +class QPainterGridDrawer : public GridDrawer { +public: + QPainterGridDrawer(QPainter *p) { m_painter = p; } + + virtual void setPen(const QPen& pen) { m_painter->setPen(pen); } + virtual void drawLine(Q_INT32 x1, Q_INT32 y1, Q_INT32 x2, Q_INT32 y2) { m_painter->drawLine(x1, y1, x2, y2); } + +private: + QPainter *m_painter; +}; + +class OpenGLGridDrawer : public GridDrawer { +public: + OpenGLGridDrawer(); + virtual ~OpenGLGridDrawer(); + + virtual void setPen(const QPen& pen); + virtual void drawLine(Q_INT32 x1, Q_INT32 y1, Q_INT32 x2, Q_INT32 y2); +}; + +#endif diff --git a/krita/ui/kis_grid_manager.cpp b/krita/ui/kis_grid_manager.cpp new file mode 100644 index 00000000..0bbbcd88 --- /dev/null +++ b/krita/ui/kis_grid_manager.cpp @@ -0,0 +1,156 @@ +/* + * This file is part of Krita + * + * 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 * parent) + : QObject(parent), m_view(parent) +{ + +} + +KisGridManager::~KisGridManager() +{ + +} + +void KisGridManager::setup(KActionCollection * collection) +{ + m_toggleGrid = new KToggleAction(i18n("Show Grid"), "", this, 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, SLOT(fastConfig1x1()), collection, "view_fast_grid_1x1"); + m_gridFastConfig2x2 = new KAction(i18n("2x2"), 0, "", this, SLOT(fastConfig2x2()), collection, "view_fast_grid_2x2"); + m_gridFastConfig5x5 = new KAction(i18n("5x5"), 0, "", this, SLOT(fastConfig5x5()), collection, "view_fast_grid_5x5"); + m_gridFastConfig10x10 = new KAction(i18n("10x10"), 0, "", this, SLOT(fastConfig10x10()), collection, "view_fast_grid_10x10"); + m_gridFastConfig20x20 = new KAction(i18n("20x20"), 0, "", this, SLOT(fastConfig20x20()), collection, "view_fast_grid_20x20"); + m_gridFastConfig40x40 = new KAction(i18n("40x40"), 0, "", this, 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(QRect wr, QPainter *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 QPainterGridDrawer(p); + } + } + + Q_ASSERT(gridDrawer != 0); + + if (gridDrawer) { + gridDrawer->drawGrid(image, wr); + delete gridDrawer; + } + } + } +} + +#include "kis_grid_manager.moc" diff --git a/krita/ui/kis_grid_manager.h b/krita/ui/kis_grid_manager.h new file mode 100644 index 00000000..bd46b5bc --- /dev/null +++ b/krita/ui/kis_grid_manager.h @@ -0,0 +1,64 @@ +/* + * This file is part of Krita + * + * 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 QObject +{ + Q_OBJECT + public: + KisGridManager(KisView * parent); + ~KisGridManager(); + public: + void setup(KActionCollection * collection); + void drawGrid(QRect wr, QPainter *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/krita/ui/kis_histogram_view.cc b/krita/ui/kis_histogram_view.cc new file mode 100644 index 00000000..67c30889 --- /dev/null +++ b/krita/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(QWidget *parent, const char *name, WFlags f) + : QLabel(parent, 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(QFrame::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; +} + +QStringList 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, QValueVector channels) +{ + setCurrentChannels( + KisHistogramProducerFactoryRegistry::instance()->get(producerID)->generate(), + channels); +} + +void KisHistogramView::setCurrentChannels(KisHistogramProducerSP producer, QValueVector 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; + } + + QValueVector 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; + QValueVector 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 + QValueVector 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(QString(" ").append(info.channel->name())); + } +} + +void KisHistogramView::updateHistogram() +{ + Q_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; + } + + Q_INT32 bins = m_histogram->producer()->numberOfBins(); + m_pix = QPixmap(bins, height); + m_pix.fill(); + QPainter p(&m_pix); + p.setBrush(Qt::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; + } + + Q_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++) { + QColor color; + m_histogram->setChannel(m_channelToOffset.at(chan)); + + if (m_color) { + color = m_channels.at(chan)->color(); + p.setPen(color); + } else { + color = Qt::black; + } + blackOnBlack = (color == Qt::black); + + if (m_histogram->getHistogramType() == LINEAR) { + double factor = (double)height / highest; + for( i=0; i= selFrom && i < selTo && blackOnBlack) { + p.setPen(Qt::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(Qt::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(QMouseEvent * e) { + if (e->button() == Qt::RightButton) + emit rightClicked(e->globalPos()); + else + QLabel::mousePressEvent(e); +} + + +#include "kis_histogram_view.moc" diff --git a/krita/ui/kis_histogram_view.h b/krita/ui/kis_histogram_view.h new file mode 100644 index 00000000..b44ee79d --- /dev/null +++ b/krita/ui/kis_histogram_view.h @@ -0,0 +1,103 @@ +/* + * 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 QLabel { + Q_OBJECT +public: + KisHistogramView(QWidget *parent = 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(); + QStringList 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, QValueVector channels); + /** Be careful, producer will be modified */ + void setCurrentChannels(KisHistogramProducerSP producer, QValueVector channels); + bool hasColor(); + void setColor(bool set); + +public slots: + void setActiveChannel(int channel); + void setHistogramType(enumHistogramType type); + void updateHistogram(); + +signals: + void rightClicked(const QPoint& pos); + +protected: + virtual void mousePressEvent(QMouseEvent * e); + +private: + void setChannels(); + void addProducerChannels(KisHistogramProducerSP producer); + + typedef struct { + bool isProducer; + KisHistogramProducerSP producer; + KisChannelInfo * channel; + } ComboboxInfo; + + QValueVector m_comboInfo; + QPixmap m_pix; + KisHistogramSP m_histogram; + KisColorSpace* m_cs; + KisHistogramProducerSP m_currentProducer; + QValueVector m_channels; + // Maps the channels in m_channels to a real channel offset in the producer->channels() + QValueVector m_channelToOffset; + QStringList m_channelStrings; + bool m_color; + double m_from; + double m_width; +}; + +#endif // _KIS_HISTOGRAM_VIEW_ diff --git a/krita/ui/kis_icon_item.cc b/krita/ui/kis_icon_item.cc new file mode 100644 index 00000000..443416cc --- /dev/null +++ b/krita/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()) { + QImage img = m_resource->img(); + + if (img.isNull()) { + m_resource->setValid(false); + m_resource = 0; + return; + } + + if (img.width() > THUMB_SIZE || img.height() > THUMB_SIZE) { + QImage thumb = img; + Q_INT32 xsize = THUMB_SIZE; + Q_INT32 ysize = THUMB_SIZE; + Q_INT32 picW = thumb.width(); + Q_INT32 picH = thumb.height(); + + if (picW > picH) { + float yFactor = (float)((float)(float)picH / (float)picW); + + ysize = (Q_INT32)(yFactor * (float)THUMB_SIZE); + + if (ysize > THUMB_SIZE) + ysize = THUMB_SIZE; + } else if (picW < picH) { + float xFactor = (float)((float)picW / (float)picH); + + xsize = (Q_INT32)(xFactor * (float)THUMB_SIZE); + + if (xsize > THUMB_SIZE) + xsize = THUMB_SIZE; + } + + thumb = thumb.smoothScale(xsize, ysize); + + if (!thumb.isNull()) { + m_thumb = QPixmap(thumb); + validThumb = !m_thumb.isNull(); + } + } + + img = img.convertDepth(32); + m_pixmap = QPixmap(img); + validPixmap = true; + } +} + +QPixmap& KisIconItem::pixmap() const +{ + return const_cast(m_pixmap); +} + +QPixmap& 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/krita/ui/kis_icon_item.h b/krita/ui/kis_icon_item.h new file mode 100644 index 00000000..7d76f05c --- /dev/null +++ b/krita/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 QPixmap& pixmap() const; + virtual QPixmap& thumbPixmap() const; + + KisResource *resource() const; + + virtual int compare(const KoIconItem *other) const; + + void updatePixmaps(); + +private: + KisResource *m_resource; + QPixmap m_pixmap; + QPixmap m_thumb; +}; + +#endif // KIS_ICON_ITEM_H_ + diff --git a/krita/ui/kis_iconwidget.cc b/krita/ui/kis_iconwidget.cc new file mode 100644 index 00000000..20f8838d --- /dev/null +++ b/krita/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(QWidget *parent, const char *name) : super(parent, name) +{ + m_item = 0; +} + +void KisIconWidget::slotSetItem(KoIconItem& item) +{ + m_item = &item; + update(); +} + +void KisIconWidget::drawButtonLabel(QPainter *p) +{ + if (m_item) { + const QPixmap& pix = m_item->pixmap(); + Q_INT32 x = 2; + Q_INT32 y = 2; + Q_INT32 pw = pix.width(); + Q_INT32 ph = pix.height(); + Q_INT32 cw = width(); + Q_INT32 ch = height(); + Q_INT32 itemWidth = 24; + Q_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 QPixmap& 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/krita/ui/kis_iconwidget.h b/krita/ui/kis_iconwidget.h new file mode 100644 index 00000000..e595dbe2 --- /dev/null +++ b/krita/ui/kis_iconwidget.h @@ -0,0 +1,49 @@ +/* + * 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 QToolButton { + typedef QToolButton super; + Q_OBJECT + +/** + * The icon widget is used in the control box where the current color and brush + * are shown. + */ +public: + KisIconWidget(QWidget *parent = 0, const char *name = 0); + +public slots: + void slotSetItem(KoIconItem& item); + +protected: + virtual void drawButtonLabel(QPainter *gc); + +private: + KoIconItem *m_item; +}; + +#endif // KIS_ICONWIDGET_H_ + diff --git a/krita/ui/kis_import_catcher.cc b/krita/ui/kis_import_catcher.cc new file mode 100644 index 00000000..656ab969 --- /dev/null +++ b/krita/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) + : QObject() + , m_doc( new KisDoc() ) + , m_image( image ) + , m_url( url ) +{ + m_doc->openURL(url); + if ( !m_doc->isLoading() ) { + slotLoadingFinished(); + } + else { + connect(m_doc, SIGNAL(loadingFinished()), this, 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->parent()->removeLayer(importedImageLayer); + } + + importedImageLayer->setName(m_url.prettyURL()); + + KisGroupLayerSP parent = 0; + KisLayerSP currentActiveLayer = m_image->activeLayer(); + + if (currentActiveLayer) { + parent = currentActiveLayer->parent(); + } + + if (parent == 0) { + parent = m_image->rootLayer(); + } + + m_image->addLayer(importedImageLayer.data(), parent, currentActiveLayer); + } + } + m_doc->deleteLater(); + deleteLater(); +} + + diff --git a/krita/ui/kis_import_catcher.h b/krita/ui/kis_import_catcher.h new file mode 100644 index 00000000..8e7777ac --- /dev/null +++ b/krita/ui/kis_import_catcher.h @@ -0,0 +1,57 @@ +/* + * 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 : QObject { + + Q_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/krita/ui/kis_input_device.cc b/krita/ui/kis_input_device.cc new file mode 100644 index 00000000..3f63e156 --- /dev/null +++ b/krita/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 + +Q_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); + +QValueVector 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(); + } +} + +QValueVector 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/krita/ui/kis_input_device.h b/krita/ui/kis_input_device.h new file mode 100644 index 00000000..91c5ff4f --- /dev/null +++ b/krita/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 QValueVector 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 QTabletEvent + static KisInputDevice eraser(); // Wacom eraser via QTabletEvent + static KisInputDevice puck(); // Wacom puck via QTabletEvent + static KisInputDevice unknown(); + +private: + KisInputDevice(Q_INT32 id) : m_id(id) {} + + Q_INT32 id() const { return m_id; } + + static void allocateDefaultDevicesIfNeeded(); + static KisInputDevice allocateNextDevice(); + +private: + Q_INT32 m_id; + + static Q_INT32 NextInputDeviceID; + static QValueVector 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/krita/ui/kis_int_spinbox.cc b/krita/ui/kis_int_spinbox.cc new file mode 100644 index 00000000..0d5d8c75 --- /dev/null +++ b/krita/ui/kis_int_spinbox.cc @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2006 Boudewijn Rempt + * Copyright (c) 2006 Casper Boemann + * + * Requires the Qt 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; + QValidator *m_validator; + QTimer m_timer; +}; + + +KisIntSpinbox::KisIntSpinbox(QWidget *parent, const char *name) + : QWidget(parent, name) +{ + init(0); +} + +KisIntSpinbox::KisIntSpinbox(const QString & /*label*/, int val, QWidget *parent, const char *name) + : QWidget(parent, name) +{ + init(val); +} + +void KisIntSpinbox::init(int val) +{ + d = new KisIntSpinboxPrivate( ); + QBoxLayout * l = new QHBoxLayout( this ); + + l->insertStretch(0, 1); + d->m_numinput = new KIntSpinBox(0, 100, 1, val, 10, this, "KisIntSpinbox::KIntSpinBox"); + + d->m_numinput->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); + d->m_numinput->setSuffix("%"); + l->addWidget( d->m_numinput ); + + d->m_slider = new KisPopupSlider(0, 100, 10, val, QSlider::Horizontal, this); + d->m_slider->setFrameStyle(QFrame::Panel|QFrame::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); + layout(); + + connect(d->m_numinput, SIGNAL(valueChanged(int)), SLOT(spinboxValueChanged(int))); + connect(d->m_slider, SIGNAL(valueChanged(int)), SLOT(sliderValueChanged(int))); + connect(d->m_slider, SIGNAL(aboutToShow()), SLOT(slotAboutToShow())); + connect(d->m_slider, SIGNAL(aboutToHide()), SLOT(slotAboutToHide())); + + connect(&(d->m_timer), SIGNAL(timeout()), this, 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); + + layout(); +} + +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 QString & /*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/krita/ui/kis_int_spinbox.h b/krita/ui/kis_int_spinbox.h new file mode 100644 index 00000000..873a2f39 --- /dev/null +++ b/krita/ui/kis_int_spinbox.h @@ -0,0 +1,198 @@ +/* + * 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 QLabel; +class QLineEdit; +class QLayout; +class QValidator; + +class KisPopupSlider : public QPopupMenu { + Q_OBJECT + +public: + + KisPopupSlider(int minValue, int maxValue, int pageStep, int value, Orientation orientation, QWidget * parent, const char * name = 0) + : QPopupMenu(parent, name) + { + m_slider = new QSlider(minValue, maxValue, pageStep, value, orientation, this, name); + //m_slider->setTracking(false); + insertItem(m_slider); + connect(m_slider, SIGNAL(valueChanged(int)), 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(QSlider::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(); } + QSlider *m_slider; + +signals: + void valueChanged(int); + +}; + +/** + * @short An input widget for integer numbers, consisting of a spinbox and + * a dropdown slider. + * + * KisIntSpinbox combines a QSpinBox and a dropdown QSlider + * to make an easy to use control for setting some integer + * parameter. + * + * + */ +class KisIntSpinbox : public QWidget +{ + + Q_OBJECT + Q_PROPERTY( int value READ value WRITE setValue ) + Q_PROPERTY( int minValue READ minValue WRITE setMinValue ) + Q_PROPERTY( int maxValue READ maxValue WRITE setMaxValue ) + +public: + + /** + * Constructs an input control for integer values + * with base 10 and initial value 0. + * + * @param parent parent QWidget + * @param name internal name for this widget + */ + KisIntSpinbox(QWidget *parent=0, const char *name=0); + /** + * Constructor + * It constructs a QSpinBox 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 parent parent QWidget + * @param name internal name for this widget + */ + KisIntSpinbox(const QString & label, int value, QWidget* parent=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 QSlider + */ + 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 QString & 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/krita/ui/kis_itemchooser.cc b/krita/ui/kis_itemchooser.cc new file mode 100644 index 00000000..b5dc03e0 --- /dev/null +++ b/krita/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(QWidget *parent, const char *name) : super(parent, name) +{ +/* m_frame = new QVBox(this); + m_frame->setFrameStyle(QFrame::Panel | QFrame::Sunken);*/ + m_chooser = new KoIconChooser(QSize(30,30), this, "icon_chooser", true); + QObject::connect(m_chooser, SIGNAL(selected(KoIconItem*)), this, 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) +{ + QPtrListIterator itr(items); + + for (itr.toFirst(); itr.current(); ++itr) + m_chooser->addItem(itr.current()); +} + +QWidget *KisItemChooser::chooserWidget() const +{ + return m_chooser; +} + +#include "kis_itemchooser.moc" + diff --git a/krita/ui/kis_itemchooser.h b/krita/ui/kis_itemchooser.h new file mode 100644 index 00000000..b9eb5913 --- /dev/null +++ b/krita/ui/kis_itemchooser.h @@ -0,0 +1,64 @@ +/* + * 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 QHBox; + +class KoIconChooser; +class KoIconItem; + +typedef QPtrList vKoIconItem; + +class KisItemChooser : public QWidget { + typedef QWidget super; + Q_OBJECT + +public: + KisItemChooser(QWidget *parent = 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; + QWidget *chooserWidget() const; + +private slots: + void slotItemSelected(KoIconItem *item); + +private: + QHBox *m_frame; + KoIconChooser *m_chooser; +}; + +#endif // KIS_ITEM_CHOOSER_H_ + diff --git a/krita/ui/kis_label_cursor_pos.cc b/krita/ui/kis_label_cursor_pos.cc new file mode 100644 index 00000000..40d2b99c --- /dev/null +++ b/krita/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(QWidget *parent, const char *name, WFlags f) : super(parent, name, f) +{ + setText("0:0"); + m_doUpdates = true; + + //setMinimumSize( 200, parent->height() - 4); +} + +KisLabelCursorPos::~KisLabelCursorPos() +{ +} + +void KisLabelCursorPos::updatePos(Q_INT32 xpos, Q_INT32 ypos) +{ + if (m_doUpdates) { + QString s; + + s.sprintf("%d:%d", xpos, ypos); + setText(s); + } +} + +void KisLabelCursorPos::enter() +{ + m_doUpdates = true; +} + +void KisLabelCursorPos::leave() +{ + m_doUpdates = false; + setText(QString::null); +} + diff --git a/krita/ui/kis_label_cursor_pos.h b/krita/ui/kis_label_cursor_pos.h new file mode 100644 index 00000000..3923c61d --- /dev/null +++ b/krita/ui/kis_label_cursor_pos.h @@ -0,0 +1,42 @@ +/* + * 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 QLabel { + Q_OBJECT + typedef QLabel super; + +public: + KisLabelCursorPos(QWidget *parent, const char *name = 0, WFlags f = 0); + virtual ~KisLabelCursorPos(); + +public slots: + void updatePos(Q_INT32 xpos, Q_INT32 ypos); + void enter(); + void leave(); + +private: + bool m_doUpdates; + Q_INT32 m_ypos; +}; + +#endif // KIS_LABEL_CURSOR_POS_H_ + diff --git a/krita/ui/kis_label_progress.cc b/krita/ui/kis_label_progress.cc new file mode 100644 index 00000000..e08a7fcf --- /dev/null +++ b/krita/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 QToolButton { + +public: + + EscapeButton(QWidget * parent, const char * name) : QToolButton(parent, name) {}; + + void keyReleaseEvent(QKeyEvent *e) + { + if (e->key()==Qt::Key_Escape) + emit clicked(); + } +}; + +KisLabelProgress::KisLabelProgress(QWidget *parent, const char *name, WFlags f) : super(parent, name, f) +{ + m_subject = 0; + m_modal = false; + + QHBoxLayout *box = new QHBoxLayout(this); + box->setAutoAdd(true); + + QIconSet cancelIconSet = SmallIconSet("stop"); + + m_cancelButton = new EscapeButton(this, "cancel_button"); + m_cancelButton->setIconSet(cancelIconSet); + QToolTip::add(m_cancelButton, i18n("Cancel")); + connect(m_cancelButton, SIGNAL(clicked()), this, 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, SIGNAL(notifyProgress(int)), this, SLOT(update(int))); + connect(subject, SIGNAL(notifyProgressStage(const QString&, int)), this, SLOT(updateStage(const QString&, int))); + connect(subject, SIGNAL(notifyProgressDone()), this, SLOT(done())); + connect(subject, SIGNAL(notifyProgressError()), this, SLOT(error())); + connect(subject, SIGNAL(destroyed()), this, 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) { + QApplication::setOverrideCursor(KisCursor::waitCursor()); + } + + m_bar->setValue(0); + } +} + +bool KisLabelProgress::event(QEvent * 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 QLabel::event(e); + }; + + return true; +} + +void KisLabelProgress::reset() +{ + if (m_subject) { + m_subject->disconnect(this); + m_subject = 0; + + if (m_modal) { + QApplication::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: + //QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput | + // QEventLoop::ExcludeSocketNotifiers); +} + +void KisLabelProgress::updateStage(const QString&, 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/krita/ui/kis_label_progress.h b/krita/ui/kis_label_progress.h new file mode 100644 index 00000000..f5385121 --- /dev/null +++ b/krita/ui/kis_label_progress.h @@ -0,0 +1,65 @@ +/* + * 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 QToolButton; +class KProgress; + +class KisLabelProgress : public QLabel, public KisProgressDisplayInterface { + Q_OBJECT + typedef QLabel super; + +public: + KisLabelProgress(QWidget *parent, const char *name = 0, WFlags f = 0); + virtual ~KisLabelProgress(); + +public: + // Implements KisProgressDisplayInterface + void setSubject(KisProgressSubject *subject, bool modal, bool canCancel); + + // Overrides QLabel::event() + bool event(QEvent * ev); + +private slots: + virtual void update(int percent); + virtual void updateStage(const QString& 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; + QToolButton *m_cancelButton; + bool m_modal; +}; + +#endif // KIS_LABEL_PROGRESS_H_ + diff --git a/krita/ui/kis_label_zoom.cc b/krita/ui/kis_label_zoom.cc new file mode 100644 index 00000000..cd8620d6 --- /dev/null +++ b/krita/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/krita/ui/kis_label_zoom.h b/krita/ui/kis_label_zoom.h new file mode 100644 index 00000000..29588368 --- /dev/null +++ b/krita/ui/kis_label_zoom.h @@ -0,0 +1,33 @@ +/* + * 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 QLabel { + Q_OBJECT + + KisLabelZoom( QWidget *parent, const char *name = 0, WFlags f = 0 ) : + QLabel( parent, name, f ) {} + virtual ~KisLabelZoom() {} + +}; + +#endif // KIS_LABEL_ZOOM_H_ + diff --git a/krita/ui/kis_layerbox.cc b/krita/ui/kis_layerbox.cc new file mode 100644 index 00000000..ef30e331 --- /dev/null +++ b/krita/ui/kis_layerbox.cc @@ -0,0 +1,675 @@ +/* + * kis_layerbox.cc - part of Krita 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, QWidget *parent, const char *name) + : super(parent, name), m_image(0) +{ + QVBoxLayout *vbox = new QVBoxLayout(this); + vbox->setAutoAdd(true); + + m_lst = new WdgLayerBox(this); + setMinimumSize(m_lst->minimumSizeHint()); + + QToolTip::add(m_lst->bnAdd, i18n("Create new layer")); + + QToolTip::add(m_lst->bnDelete, i18n("Remove current layer")); + + QToolTip::add(m_lst->bnRaise, i18n("Raise current layer")); + m_lst->bnRaise->setEnabled(false); + + m_lst->bnLower->setEnabled(false); + QToolTip::add(m_lst->bnLower, i18n("Lower current layer")); + + QToolTip::add(m_lst->bnProperties, i18n("Properties for layer")); + + KIconLoader il( "krita" ); + + 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(), SIGNAL(aboutToShow()), SLOT(slotAboutToShow())); + connect(list(), SIGNAL(activated(LayerItem*)), + SLOT(slotLayerActivated(LayerItem*))); + connect(list(), SIGNAL(displayNameChanged(LayerItem*, const QString&)), + SLOT(slotLayerDisplayNameChanged(LayerItem*, const QString&))); + connect(list(), SIGNAL(propertyChanged(LayerItem*, const QString&, bool)), + SLOT(slotLayerPropertyChanged(LayerItem*, const QString&, bool))); + connect(list(), SIGNAL(layerMoved(LayerItem*, LayerItem*, LayerItem*)), + SLOT(slotLayerMoved(LayerItem*, LayerItem*, LayerItem*))); + connect(list(), SIGNAL(requestNewLayer(LayerItem*, LayerItem*)), + SLOT(slotRequestNewLayer(LayerItem*, LayerItem*))); + connect(list(), SIGNAL(requestNewFolder(LayerItem*, LayerItem*)), + SLOT(slotRequestNewFolder(LayerItem*, LayerItem*))); + connect(list(), SIGNAL(requestNewAdjustmentLayer(LayerItem*, LayerItem*)), + SLOT(slotRequestNewAdjustmentLayer(LayerItem*, LayerItem*))); + connect(list(), SIGNAL(requestNewObjectLayer(LayerItem*, LayerItem*, const KoDocumentEntry&)), + SLOT(slotRequestNewObjectLayer(LayerItem*, LayerItem*, const KoDocumentEntry&))); + connect(list(), SIGNAL(requestRemoveLayer(LayerItem*)), + SLOT(slotRequestRemoveLayer(LayerItem*))); + connect(list(), SIGNAL(requestLayerProperties(LayerItem*)), + 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", this ); + m_partLayerAction->plug( m_newLayerMenu ); + connect(m_partLayerAction, SIGNAL(activated()), this, SLOT(slotAddMenuActivated())); + connect(m_newLayerMenu, SIGNAL(activated(int)), this, SLOT(slotAddMenuActivated(int))); + + + connect(m_lst->bnDelete, SIGNAL(clicked()), SLOT(slotRmClicked())); + connect(m_lst->bnRaise, SIGNAL(clicked()), SLOT(slotRaiseClicked())); + connect(m_lst->bnLower, SIGNAL(clicked()), SLOT(slotLowerClicked())); + connect(m_lst->bnProperties, SIGNAL(clicked()), SLOT(slotPropertiesClicked())); + connect(m_lst->intOpacity, SIGNAL(valueChanged(int, bool)), SIGNAL(sigOpacityChanged(int, bool))); + connect(m_lst->intOpacity, SIGNAL(finishedChanging(int, int)), SIGNAL(sigOpacityFinishedChanging(int, int))); + connect(m_lst->cmbComposite, SIGNAL(activated(const KisCompositeOp&)), SIGNAL(sigItemComposite(const KisCompositeOp&))); + + Q_ASSERT(subject->document() != 0); + + if (subject->document()) { + connect(subject->document(), SIGNAL(sigCommandExecuted()), 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, SIGNAL(sigLayerActivated(KisLayerSP)), this, SLOT(slotLayerActivated(KisLayerSP))); + connect(img, SIGNAL(sigLayerAdded(KisLayerSP)), this, SLOT(slotLayerAdded(KisLayerSP))); + connect(img, SIGNAL(sigLayerRemoved(KisLayerSP, KisGroupLayerSP, KisLayerSP)), + this, SLOT(slotLayerRemoved(KisLayerSP, KisGroupLayerSP, KisLayerSP))); + connect(img, SIGNAL(sigLayerPropertiesChanged(KisLayerSP)), + this, SLOT(slotLayerPropertiesChanged(KisLayerSP))); + connect(img, SIGNAL(sigLayerMoved(KisLayerSP, KisGroupLayerSP, KisLayerSP)), + this, SLOT(slotLayerMoved(KisLayerSP, KisGroupLayerSP, KisLayerSP))); + connect(img, SIGNAL(sigLayersChanged(KisGroupLayerSP)), this, SLOT(slotLayersChanged(KisGroupLayerSP))); + connect(img, SIGNAL(sigLayerUpdated(KisLayerSP, QRect)), this, SLOT(slotLayerUpdated(KisLayerSP, QRect))); + 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->parent() == m_image->rootLayer()) + { + KisPopulateVisitor visitor(list()); + layer->accept(visitor); + layersAdded = visitor.layersAdded(); + } + else + { + KisPopulateVisitor visitor(static_cast(list()->layer(layer->parent()->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 parentID = layer->parent()->id(); + if (layer->parent() == m_image->rootLayer()) + parentID = -1; + + int siblingID = -1; + if (layer->prevSibling()) + siblingID = layer->prevSibling()->id(); + + list()->moveLayer(layer->id(), parentID, siblingID); + + markModified(layer->parent()); + 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 (QListViewItemIterator it(list()->lastItem()); *it; --it) + m_modified.append(static_cast(*it)->id()); + updateUI(); +} + +void KisLayerBox::slotLayerUpdated(KisLayerSP layer, QRect) +{ + 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 QString& displayName) +{ + if(KisLayerSP layer = m_image->findLayer(item->id())) + layer->setName(displayName); + updateUI(); +} + +void KisLayerBox::slotLayerPropertyChanged(LayerItem* item, const QString& 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 parent; + if( item->parent() ) + parent = dynamic_cast(m_image->findLayer(item->parent()->id()).data()); + if( !parent ) + parent = m_image->rootLayer(); + KisLayerSP above = 0; + if (item->nextSibling()) + above = m_image->findLayer(item->nextSibling()->id()); + if (layer) + m_image->moveLayer(layer, parent.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 parent = 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 = parent->firstChild(); + else if (!p && m_image->rootLayer()->childCount()) + above = m_image->rootLayer()->firstChild(); + emit sigRequestLayer(parent, 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 parent = 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 = parent->firstChild(); + else if (!p && m_image->rootLayer()->childCount()) + above = m_image->rootLayer()->firstChild(); + emit sigRequestGroupLayer(parent, 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 parent = 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 = parent->firstChild(); + else if (!p && m_image->rootLayer()->childCount()) + above = m_image->rootLayer()->firstChild(); + emit sigRequestAdjustmentLayer(parent, 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 parent = 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 = parent->firstChild(); + else if (!p && m_image->rootLayer()->childCount()) + above = m_image->rootLayer()->firstChild(); + emit sigRequestPartLayer(parent, 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()->parent())); + 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 parent; + KisLayerSP above; + if (KisLayerSP active = m_image->activeLayer()) + { + parent = root; + above = active; + if (active->parent()) + parent = active->parent(); + } + else + { + parent = root; + above = m_image->rootLayer()->firstChild(); + } + + switch (type) + { + case PAINT_LAYER: + emit sigRequestLayer(parent, above); + break; + case GROUP_LAYER: + emit sigRequestGroupLayer(parent, above); + break; + case ADJUSTMENT_LAYER: + emit sigRequestAdjustmentLayer(parent, above); + break; + case OBJECT_LAYER: + default: //goddamned Qt doesn't emit activated for default-assigned IDs, so this does nothing + emit sigRequestPartLayer(parent, above, m_partLayerAction->documentEntry()); + } +} + +void KisLayerBox::slotRmClicked() +{ + QValueList l = list()->selectedLayerIDs(); + if (l.count() < 2 && list()->activeLayer() && !l.contains(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() +{ + QValueList l = list()->selectedLayerIDs(); + if (l.count() < 2 && list()->activeLayer() && !l.contains(list()->activeLayer()->id())) + { + l.clear(); + l.append(list()->activeLayer()->id()); + } + + KisLayerSP layer = m_image->findLayer(l.first()); + if( l.count() == 1 && layer == layer->parent()->firstChild() && layer->parent() != m_image->rootLayer()) + { + if (KisGroupLayerSP grandparent = layer->parent()->parent()) + m_image->moveLayer(layer, grandparent, layer->parent().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->parent(), li->prevSibling()); + } + + if( !l.isEmpty() ) + list()->ensureItemVisible( list()->layer( l.first() ) ); +} + +void KisLayerBox::slotLowerClicked() +{ + QValueList l = list()->selectedLayers(); + if (l.count() < 2 && list()->activeLayer() && !l.contains(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->parent(), 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); +} + + +QPixmap KisLayerBox::loadPixmap(const QString& filename, const KIconLoader& + il, int size) +{ + QPixmap pixmap = il.loadIcon(filename, KIcon::NoGroup, size); + + if (pixmap.isNull()) + KMessageBox::error(0, i18n("Cannot find %1").arg(filename), + i18n("Canvas")); + + return pixmap; +} + +void KisLayerBox::markModified(KisLayer* layer) +{ + if( !layer ) + return; + + QValueList v; + while (layer && layer != m_image->rootLayer().data()) + { + v.append(layer->id()); + layer = layer->parent(); + } + for (int i = v.count() - 1; i >= 0; --i) + if (!m_modified.contains(v[i])) + m_modified.append(v[i]); +} + +void KisLayerBox::printKritaLayers() const +{ + static int indent = 0; + static KisLayer *root = 0; + if( !root ) + root = m_image->rootLayer(); + if( !root ) + return; + QString s = root->name(); + if( dynamic_cast( root ) ) + s = QString("[%1]").arg( s ); + if( m_image->activeLayer().data() == root ) + s.prepend("*"); + kdDebug() << (QString().fill(' ', indent) + s) << endl; + for (KisLayer* layer = root->firstChild(); layer; layer = layer->nextSibling()) + { + indent += 2; + root = layer; + printKritaLayers(); + indent -= 2; + root = layer->parent(); + } +} + +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->parent(); + } + return; + } + QString s = root->displayName(); + if( root->isFolder() ) + s = QString("[%1]").arg( s ); + if( list()->activeLayer() == root ) + s.prepend("*"); + kdDebug() << (QString().fill(' ', indent) + s) << endl; + for (LayerItem* layer = root->firstChild(); layer; layer = layer->nextSibling()) + { + indent += 2; + root = layer; + printLayerboxLayers(); + indent -= 2; + root = layer->parent(); + } +} + +#include "kis_layerbox.moc" diff --git a/krita/ui/kis_layerbox.h b/krita/ui/kis_layerbox.h new file mode 100644 index 00000000..dab83d63 --- /dev/null +++ b/krita/ui/kis_layerbox.h @@ -0,0 +1,123 @@ +/* + * kis_layerbox.h - part of Krita 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 QButton; +class QPainter; +class QWidget; +class KIconLoader; +class KPopupMenu; +class KoDocumentEntry; +class KisCompositeOp; +class KisLayerList; +class LayerItem; +class KisCanvasSubject; + +class KisLayerBox : public QFrame { + typedef QFrame super; + Q_OBJECT + +public: + KisLayerBox(KisCanvasSubject *subject, QWidget *parent = 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, QRect rc); + + void slotSetCompositeOp(const KisCompositeOp& compositeOp); + void slotSetOpacity(int opacity); + void slotSetColorSpace(const KisColorSpace * colorSpace); + +signals: + void sigRequestLayer(KisGroupLayerSP parent, KisLayerSP above); + void sigRequestGroupLayer(KisGroupLayerSP parent, KisLayerSP above); + void sigRequestAdjustmentLayer(KisGroupLayerSP parent, KisLayerSP above); + void sigRequestPartLayer(KisGroupLayerSP parent, 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 QString& displayName); + void slotLayerPropertyChanged(LayerItem* layer, const QString& name, bool on); + void slotLayerMoved(LayerItem* layer, LayerItem* parent, LayerItem* after); + void slotRequestNewLayer(LayerItem* parent, LayerItem* after); + void slotRequestNewFolder(LayerItem* parent, LayerItem* after); + void slotRequestNewAdjustmentLayer(LayerItem* parent, LayerItem* after); + void slotRequestNewObjectLayer(LayerItem* parent, 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(); + QPixmap loadPixmap(const QString& filename, const KIconLoader& il, int size); + KisLayerList* list() const; + void markModified(KisLayer *layer); + + KPopupMenu *m_newLayerMenu; + KoPartSelectAction *m_partLayerAction; + KisImageSP m_image; + QValueList m_modified; + WdgLayerBox *m_lst; + + void printKritaLayers() const; + void printLayerboxLayers() const; +}; + +#endif // KIS_LAYERBOX_H + diff --git a/krita/ui/kis_layerlist.cc b/krita/ui/kis_layerlist.cc new file mode 100644 index 00000000..356d7e39 --- /dev/null +++ b/krita/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( QWidget *parent, const char *name ) + : super( parent, name ) +{ + m_partLayerAction = new KoPartSelectAction( i18n( "New &Object Layer" ), "gear", 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 QValueList selected = selectedLayers(); + LayerItem *parent = ( layer && layer->isFolder() ) ? layer : 0; + LayerItem *after = 0; + if( layer && !parent ) + { + parent = layer->parent(); + after = layer->prevSibling(); + } + switch( id ) + { + case MenuItems::NewLayer: + emit requestNewLayer( parent, after ); + emit requestNewLayer( parent ? parent->id() : -1, after ? after->id() : -1 ); + break; + case MenuItems::NewFolder: + emit requestNewFolder( parent, after ); + emit requestNewFolder( parent ? parent->id() : -1, after ? after->id() : -1 ); + break; + case ADJUSTMENT_LAYER: + emit requestNewAdjustmentLayer( parent, after ); + emit requestNewAdjustmentLayer( parent ? parent->id() : -1, after ? after->id() : -1 ); + break; + case MenuItems::RemoveLayer: + { + QValueList 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( parent, after, m_partLayerAction->documentEntry() ); + emit requestNewObjectLayer( parent ? parent->id() : -1, after ? after->id() : -1, m_partLayerAction->documentEntry() ); + } + } +} + +KisLayerItem::KisLayerItem( LayerList* parent, KisLayer* layer ) + : super( layer->name(), + parent, + layer->prevSibling() ? parent->layer( layer->prevSibling()->id() ) : 0, + layer->id() ) + , m_layer( layer ) +{ + init(); +} + +KisLayerItem::KisLayerItem( LayerItem* parent, KisLayer* layer ) + : super( layer->name(), + parent, + layer->prevSibling() ? parent->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(); +} + +QString KisLayerItem::tooltip() const +{ + QString text = super::tooltip(); + text = text.left( text.length() - 8 ); //HACK -- strip the + QString row = "%1%2"; + text += row.arg( i18n( "Opacity:" ) ).arg( "%1%" ).arg( int( float( m_layer->opacity() * 100 ) / 255 + 0.5 ) ); + text += row.arg( i18n( "Composite mode:" ) ).arg( m_layer->compositeOp().id().name() ); + if( KisPaintLayer *player = dynamic_cast( m_layer ) ) + { + text += row.arg( i18n( "Colorspace:" ) ).arg( player->paintDevice()->colorSpace()->id().name() ); + if( KisProfile *profile = player->paintDevice()->colorSpace()->getProfile() ) + text += row.arg( i18n( "Profile:" ) ).arg( profile->productName() ); + } + if( KisAdjustmentLayer *alayer = dynamic_cast( m_layer ) ) + text += row.arg( i18n( "Filter: " ) ).arg( KisFilterRegistry::instance()->get( alayer->filter()->name() )->id().name() ); + if( KisPartLayerImpl *player = dynamic_cast( m_layer ) ) { + QString type = player->docType(); + + if( type.isEmpty() ) { + type = player->childDoc()->document()->instance()->aboutData()->programName(); + } + + text += row.arg( i18n( "Document type: " ) ).arg( type ); + } + text += ""; + + return text; +} + +QImage KisLayerItem::tooltipPreview() const +{ + QImage img = m_layer->createThumbnail( 400, 400 ); + if( img.isNull() ) + return img; //so Qt doesn't complain + img.setAlphaBuffer( true ); + const int size = kMin( 200, kMax( img.width(), img.height() ) ); + return img.smoothScale( size, size, QImage::ScaleMin ); +} + +//void KisLayerItem::paintCell( QPainter *p, const QColorGroup &cg, int column, int width, int align ); + +#include "kis_layerlist.moc" diff --git a/krita/ui/kis_layerlist.h b/krita/ui/kis_layerlist.h new file mode 100644 index 00000000..e3bacdfd --- /dev/null +++ b/krita/ui/kis_layerlist.h @@ -0,0 +1,79 @@ +/* + 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 + typedef LayerList super; + +signals: + void requestNewObjectLayer( LayerItem *parent, LayerItem *after, const KoDocumentEntry &entry ); + void requestNewObjectLayer( int parentID, int afterID, const KoDocumentEntry &entry ); + void requestNewAdjustmentLayer( LayerItem *parent, LayerItem *after ); + void requestNewAdjustmentLayer( int parentID, int afterID ); + +public: + KisLayerList( QWidget *parent = 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* parent, KisLayer* layer ); + KisLayerItem( LayerItem* parent, KisLayer* layer ); + + KisLayer* layer() const; + + void sync(); + + /// returns whether any preview was retrieved + bool updatePreview(); + + virtual QString tooltip() const; + virtual QImage tooltipPreview() const; + + //virtual void paintCell( QPainter *p, const QColorGroup &cg, int column, int width, int align ); + +private: + void init(); + QImage m_preview; + KisLayer *m_layer; +}; + +#endif diff --git a/krita/ui/kis_load_visitor.h b/krita/ui/kis_load_visitor.h new file mode 100644 index 00000000..ff1c1cf8 --- /dev/null +++ b/krita/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, QMap &layerFilenames) : + KisLayerVisitor(), + m_layerFilenames(layerFilenames) + { + m_external = false; + m_img = img; + m_store = store; + } + +public: + void setExternalUri(QString &uri) + { + m_external = true; + m_uri = uri; + } + + virtual bool visit(KisPaintLayer *layer) + { //connect(*layer->paintDevice(), SIGNAL(ioProgress(Q_INT8)), m_img, SLOT(slotIOProgress(Q_INT8))); + + QString location = m_external ? QString::null : 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 ? QString::null : m_uri; + location += m_img->name() + "/layers/" + m_layerFilenames[layer] + ".icc"; + + if (m_store->hasFile(location)) { + QByteArray 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); + QRect 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; + } + + // mask + if (layer->hasMask()) { // We set this in KisDoc::loadPaintLayer + KisPaintDeviceSP mask = layer->getMask(); + location = m_external ? QString::null : m_uri; + location += m_img->name() + "/layers/" + m_layerFilenames[layer] + ".mask"; + + // Layer data + if (m_store->open(location)) { + if (!mask->read(m_store)) { + mask->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(), SIGNAL(ioProgress(Q_INT8)), m_img, SLOT(slotIOProgress(Q_INT8))); + + // The selection -- if present. If not, we simply cannot open the dratted thing. + QString location = m_external ? QString::null : 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 ? QString::null : m_uri; + location += m_img->name() + "/layers/" + m_layerFilenames[layer] + ".filterconfig"; + + if (m_store->hasFile(location) && layer->filter()) { + QByteArray data; + m_store->open(location); + data = m_store->read(m_store->size()); + m_store->close(); + if (data) { + KisFilterConfiguration * kfc = layer->filter(); + kfc->fromXML(QString(data)); + } + } + + return true; + + } + +private: + KisImageSP m_img; + KoStore *m_store; + bool m_external; + QString m_uri; + QMap m_layerFilenames; +}; + +#endif // KIS_LOAD_VISITOR_H_ + diff --git a/krita/ui/kis_matrix_widget.ui b/krita/ui/kis_matrix_widget.ui new file mode 100644 index 00000000..dda7d63c --- /dev/null +++ b/krita/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/krita/ui/kis_matrix_widget.ui.h b/krita/ui/kis_matrix_widget.ui.h new file mode 100644 index 00000000..a0b06224 --- /dev/null +++ b/krita/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 +** Qt 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/krita/ui/kis_move_event.h b/krita/ui/kis_move_event.h new file mode 100644 index 00000000..5a7b0ca9 --- /dev/null +++ b/krita/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, Qt::ButtonState state) : super(MoveEvent, device, pos, globalPos, pressure, xTilt, yTilt, state) {} +}; + +#endif // KIS_MOVE_EVENT_H_ + diff --git a/krita/ui/kis_multi_bool_filter_widget.cc b/krita/ui/kis_multi_bool_filter_widget.cc new file mode 100644 index 00000000..d5904287 --- /dev/null +++ b/krita/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, QString nlabel, QString nname) : + initvalue(ninitvalue), + label(nlabel), + name(nname) +{ + +} + +KisMultiBoolFilterWidget::KisMultiBoolFilterWidget(QWidget * parent, const char * name, const char * caption, vKisBoolWidgetParam iwparam) : + KisFilterConfigWidget( parent, name ) +{ + Q_INT32 m_nbboolWidgets = iwparam.size(); + + this->setCaption(caption); + + QVBoxLayout *widgetLayout = new QVBoxLayout(this, m_nbboolWidgets + 1); + + m_boolWidgets = new QCheckBox*[ m_nbboolWidgets ]; + + for( Q_INT32 i = 0; i < m_nbboolWidgets; ++i) + { + m_boolWidgets[i] = new QCheckBox( this, iwparam[i].name.ascii()); + m_boolWidgets[i]->setChecked( iwparam[i].initvalue ); + m_boolWidgets[i]->setText( iwparam[i].label ); + connect(m_boolWidgets[i], SIGNAL(toggled( bool ) ), SIGNAL(sigPleaseUpdatePreview())); + widgetLayout->add( m_boolWidgets[i]); + } +// QSpacerItem * sp = new QSpacerItem(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/krita/ui/kis_multi_bool_filter_widget.h b/krita/ui/kis_multi_bool_filter_widget.h new file mode 100644 index 00000000..b9b4b2d7 --- /dev/null +++ b/krita/ui/kis_multi_bool_filter_widget.h @@ -0,0 +1,55 @@ +/* + * 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, QString label, QString name); + bool initvalue; + QString label; + QString name; + +}; + +typedef std::vector vKisBoolWidgetParam; + +class KRITA_EXPORT KisMultiBoolFilterWidget : public KisFilterConfigWidget +{ + Q_OBJECT +public: + KisMultiBoolFilterWidget(QWidget * parent, const char * name, const char *caption, vKisBoolWidgetParam iwparam); + virtual void setConfiguration(KisFilterConfiguration * cfg); +public: + inline Q_INT32 nbValues() { return m_nbboolWidgets; }; + inline Q_INT32 valueAt( Q_INT32 i ) { return m_boolWidgets[i]->isChecked(); }; +private: + QCheckBox** m_boolWidgets; + Q_INT32 m_nbboolWidgets; +}; + +#endif diff --git a/krita/ui/kis_multi_double_filter_widget.cc b/krita/ui/kis_multi_double_filter_widget.cc new file mode 100644 index 00000000..024b0368 --- /dev/null +++ b/krita/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(QWidget * parent, const char * name) + : KDoubleNumInput(parent, name) +{ + m_timer = new QTimer(this, name); + connect(m_timer, SIGNAL(timeout()), SLOT(slotValueChanged())); + connect(this, SIGNAL(valueChanged( double )), 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, QString nlabel, QString nname) : + min(nmin), + max(nmax), + initvalue(ninitvalue), + label(nlabel), + name(nname) +{ + +} + +KisMultiDoubleFilterWidget::KisMultiDoubleFilterWidget(QWidget * parent, const char * name, const char * caption, vKisDoubleWidgetParam dwparam) + : KisFilterConfigWidget( parent, name ) +{ + Q_INT32 m_nbdoubleWidgets = dwparam.size(); + + this->setCaption(caption); + + QGridLayout *widgetLayout = new QGridLayout(this, m_nbdoubleWidgets + 1, 3); + widgetLayout->setColStretch ( 1, 1 ); + + m_doubleWidgets = new KisDelayedActionDoubleInput*[ m_nbdoubleWidgets ]; + + for( Q_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], SIGNAL(valueChangedDelayed(double)), SIGNAL(sigPleaseUpdatePreview())); + + QLabel* lbl = new QLabel(dwparam[i].label+":", this); + widgetLayout->addWidget( lbl, i , 0); + + widgetLayout->addWidget( m_doubleWidgets[i], i , 1); + } + QSpacerItem * sp = new QSpacerItem(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/krita/ui/kis_multi_double_filter_widget.h b/krita/ui/kis_multi_double_filter_widget.h new file mode 100644 index 00000000..bd1cf235 --- /dev/null +++ b/krita/ui/kis_multi_double_filter_widget.h @@ -0,0 +1,77 @@ +/* + * 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 + + public: + + KisDelayedActionDoubleInput(QWidget * parent, const char * name); + + void cancelDelayedSignal(); + + private slots: + void slotValueChanged(); + void slotTimeToUpdate(); + + signals: + + void valueChangedDelayed(double value); + + private: + + QTimer * m_timer; +}; + + +struct KRITA_EXPORT KisDoubleWidgetParam { + KisDoubleWidgetParam( double nmin, double nmax, double ninitvalue, QString label, QString nname); + double min; + double max; + double initvalue; + QString label; + QString name; +}; + +typedef std::vector vKisDoubleWidgetParam; + +class KRITA_EXPORT KisMultiDoubleFilterWidget : public KisFilterConfigWidget +{ + Q_OBJECT +public: + KisMultiDoubleFilterWidget(QWidget * parent, const char * name, const char * caption, vKisDoubleWidgetParam dwparam); + virtual void setConfiguration(KisFilterConfiguration * cfg); +public: + inline Q_INT32 nbValues() { return m_nbdoubleWidgets; }; + inline double valueAt( Q_INT32 i ) { return m_doubleWidgets[i]->value(); }; +private: + KisDelayedActionDoubleInput** m_doubleWidgets; + Q_INT32 m_nbdoubleWidgets; +}; + +#endif diff --git a/krita/ui/kis_multi_integer_filter_widget.cc b/krita/ui/kis_multi_integer_filter_widget.cc new file mode 100644 index 00000000..be50022d --- /dev/null +++ b/krita/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(QWidget * parent, const char * name) + : KIntNumInput(parent, name) +{ + m_timer = new QTimer(this, name); + connect(m_timer, SIGNAL(timeout()), SLOT(slotValueChanged())); + connect(this, SIGNAL(valueChanged( int )), SLOT(slotTimeToUpdate())); +} + +void KisDelayedActionIntegerInput::slotTimeToUpdate() +{ + m_timer->start(50, true); +} + +void KisDelayedActionIntegerInput::slotValueChanged() +{ + emit valueChangedDelayed( value() ); +} + +void KisDelayedActionIntegerInput::cancelDelayedSignal() +{ + m_timer->stop(); +} + +KisIntegerWidgetParam::KisIntegerWidgetParam( Q_INT32 nmin, Q_INT32 nmax, Q_INT32 ninitvalue, QString label, QString nname) : + min(nmin), + max(nmax), + initvalue(ninitvalue), + label(label), + name(nname) +{ +} + +KisMultiIntegerFilterWidget::KisMultiIntegerFilterWidget(QWidget * parent, + const char * name, + const char * caption, + vKisIntegerWidgetParam iwparam) + : KisFilterConfigWidget( parent, name ) +{ + m_nbintegerWidgets = iwparam.size(); + this->setCaption(caption); + + QGridLayout *widgetLayout = new QGridLayout(this, m_nbintegerWidgets + 1, 3); + widgetLayout->setColStretch ( 1, 1 ); + + m_integerWidgets = new KisDelayedActionIntegerInput*[ m_nbintegerWidgets ]; + + for( Q_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], SIGNAL(valueChangedDelayed( int )), SIGNAL(sigPleaseUpdatePreview())); + + QLabel* lbl = new QLabel(iwparam[i].label+":", this); + widgetLayout->addWidget( lbl, i , 0); + + widgetLayout->addWidget( m_integerWidgets[i], i , 1); + } + QSpacerItem * sp = new QSpacerItem(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/krita/ui/kis_multi_integer_filter_widget.h b/krita/ui/kis_multi_integer_filter_widget.h new file mode 100644 index 00000000..fe0ececf --- /dev/null +++ b/krita/ui/kis_multi_integer_filter_widget.h @@ -0,0 +1,81 @@ +/* + * 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 + +public: + + KisDelayedActionIntegerInput(QWidget * parent, const char * name); + + void cancelDelayedSignal(); + +private slots: + void slotValueChanged(); + void slotTimeToUpdate(); + +signals: + + void valueChangedDelayed(int value); + +private: + + QTimer * m_timer; +}; + + +struct KisIntegerWidgetParam { + KRITA_EXPORT KisIntegerWidgetParam( Q_INT32 nmin, Q_INT32 nmax, Q_INT32 ninitvalue, QString label, QString nname); + Q_INT32 min; + Q_INT32 max; + Q_INT32 initvalue; + QString label; + QString name; +}; + +typedef std::vector vKisIntegerWidgetParam; + +class KRITA_EXPORT KisMultiIntegerFilterWidget : public KisFilterConfigWidget +{ + Q_OBJECT +public: + KisMultiIntegerFilterWidget(QWidget * parent, const char * name, const char *caption, vKisIntegerWidgetParam iwparam); + + virtual void setConfiguration(KisFilterConfiguration * config); + +public: + inline Q_INT32 nbValues() { return m_nbintegerWidgets; }; + inline Q_INT32 valueAt( Q_INT32 i ) { return m_integerWidgets[i]->value(); }; + +private: + Q_INT32 m_nbintegerWidgets; + KisDelayedActionIntegerInput** m_integerWidgets; +}; + +#endif diff --git a/krita/ui/kis_opengl_canvas.cc b/krita/ui/kis_opengl_canvas.cc new file mode 100644 index 00000000..0ec9ec72 --- /dev/null +++ b/krita/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(QWidget *parent, const char *name, QGLWidget *sharedContextWidget) + : QGLWidget(KisOpenGLCanvasFormat, parent, name, sharedContextWidget) +{ + if (isSharing()) { + kdDebug(41001) << "Created QGLWidget with sharing\n"; + } else { + kdDebug(41001) << "Created QGLWidget with no sharing\n"; + } +} + +KisOpenGLCanvasWidget::~KisOpenGLCanvasWidget() +{ +} + +void KisOpenGLCanvasWidget::paintEvent(QPaintEvent *e) +{ + QGLWidget::paintEvent(e); + + widgetGotPaintEvent(e); +} + +void KisOpenGLCanvasWidget::mousePressEvent(QMouseEvent *e) +{ + widgetGotMousePressEvent(e); +} + +void KisOpenGLCanvasWidget::mouseReleaseEvent(QMouseEvent *e) +{ + widgetGotMouseReleaseEvent(e); +} + +void KisOpenGLCanvasWidget::mouseDoubleClickEvent(QMouseEvent *e) +{ + widgetGotMouseDoubleClickEvent(e); +} + +void KisOpenGLCanvasWidget::mouseMoveEvent(QMouseEvent *e) +{ + widgetGotMouseMoveEvent(e); +} + +void KisOpenGLCanvasWidget::tabletEvent(QTabletEvent *e) +{ + widgetGotTabletEvent(e); +} + +void KisOpenGLCanvasWidget::enterEvent(QEvent *e) +{ + widgetGotEnterEvent(e); +} + +void KisOpenGLCanvasWidget::leaveEvent(QEvent *e) +{ + widgetGotLeaveEvent(e); +} + +void KisOpenGLCanvasWidget::wheelEvent(QWheelEvent *e) +{ + widgetGotWheelEvent(e); +} + +void KisOpenGLCanvasWidget::keyPressEvent(QKeyEvent *e) +{ + widgetGotKeyPressEvent(e); +} + +void KisOpenGLCanvasWidget::keyReleaseEvent(QKeyEvent *e) +{ + widgetGotKeyReleaseEvent(e); +} + +void KisOpenGLCanvasWidget::dragEnterEvent(QDragEnterEvent *e) +{ + widgetGotDragEnterEvent(e); +} + +void KisOpenGLCanvasWidget::dropEvent(QDropEvent *e) +{ + widgetGotDropEvent(e); +} + +#ifdef Q_WS_X11 + +bool KisOpenGLCanvasWidget::x11Event(XEvent *event) +{ + return KisCanvasWidget::x11Event(event, x11Display(), winId(), mapToGlobal(QPoint(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/krita/ui/kis_opengl_canvas.h b/krita/ui/kis_opengl_canvas.h new file mode 100644 index 00000000..3e7231d7 --- /dev/null +++ b/krita/ui/kis_opengl_canvas.h @@ -0,0 +1,72 @@ +/* + * 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_WS_X11 +#include +#endif // Q_WS_X11 + +#define KisOpenGLCanvasFormat (QGL::DoubleBuffer|QGL::Rgba|QGL::DirectRendering|QGL::NoDepthBuffer) + +class KisOpenGLCanvasWidget : public virtual QGLWidget, public virtual KisCanvasWidget { +public: + KisOpenGLCanvasWidget(QWidget *parent, const char *name, QGLWidget *sharedContextWidget); + ~KisOpenGLCanvasWidget(); + + virtual KisCanvasWidgetPainter *createPainter(); + +#if defined(EXTENDED_X11_TABLET_SUPPORT) + virtual void selectTabletDeviceEvents(); +#endif + +protected: + virtual void paintEvent(QPaintEvent *event); + virtual void mousePressEvent(QMouseEvent *event); + virtual void mouseReleaseEvent(QMouseEvent *event); + virtual void mouseDoubleClickEvent(QMouseEvent *event); + virtual void mouseMoveEvent(QMouseEvent *event); + virtual void tabletEvent(QTabletEvent *event); + virtual void enterEvent(QEvent *event ); + virtual void leaveEvent(QEvent *event); + virtual void wheelEvent(QWheelEvent *event); + virtual void keyPressEvent(QKeyEvent *event); + virtual void keyReleaseEvent(QKeyEvent *event); + virtual void dragEnterEvent(QDragEnterEvent *event); + virtual void dropEvent(QDropEvent *event); +#ifdef Q_WS_X11 + bool x11Event(XEvent *event); +#endif // Q_WS_X11 +}; +#endif // HAVE_GL + +#endif // KIS_OPENGL_CANVAS_H_ + diff --git a/krita/ui/kis_opengl_canvas_painter.cc b/krita/ui/kis_opengl_canvas_painter.cc new file mode 100644 index 00000000..06e38997 --- /dev/null +++ b/krita/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(QGLWidget *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 = QRect(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 Qt 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 == Qt::SolidLine) { + glDisable(GL_LINE_STIPPLE); + } else { + GLushort lineStipple; + + switch (penStyle) { + case Qt::NoPen: + lineStipple = 0; + break; + default: + case Qt::DashLine: + lineStipple = 0x3fff; + break; + case Qt::DotLine: + lineStipple = 0x3333; + break; + case Qt::DashDotLine: + lineStipple = 0x33ff; + break; + case Qt::DashDotDotLine: + lineStipple = 0x333f; + break; + } + + glEnable(GL_LINE_STIPPLE); + glLineStipple(1, lineStipple); + } +} + +QFontMetrics KisOpenGLCanvasPainter::fontMetrics() const +{ + return QFontMetrics(QFont()); +} + +QFontInfo KisOpenGLCanvasPainter::fontInfo() const +{ + return QFontInfo(QFont()); +} + +const QFont& KisOpenGLCanvasPainter::font() const +{ + return m_defaultFont; +} + +void KisOpenGLCanvasPainter::setFont(const QFont& /*font*/) +{ +} + +const QPen& KisOpenGLCanvasPainter::pen() const +{ + return m_defaultPen; +} + +void KisOpenGLCanvasPainter::setPen(const QPen& pen) +{ + setPenStyle(pen.style()); +} + +void KisOpenGLCanvasPainter::setPen(Qt::PenStyle penStyle) +{ + setPenStyle(penStyle); +} + +void KisOpenGLCanvasPainter::setPen(const QColor& /*color*/) +{ +} + +const QBrush& KisOpenGLCanvasPainter::brush() const +{ + return m_defaultBrush; +} + +void KisOpenGLCanvasPainter::setBrush(const QBrush& /*brush*/) +{ +} + +void KisOpenGLCanvasPainter::setBrush(Qt::BrushStyle /*brushStyle*/) +{ +} + +void KisOpenGLCanvasPainter::setBrush(const QColor& /*color*/) +{ +} + +QPoint KisOpenGLCanvasPainter::pos() const +{ + return QPoint(); +} + +const QColor& KisOpenGLCanvasPainter::backgroundColor() const +{ + return m_defaultColor; +} + +void KisOpenGLCanvasPainter::setBackgroundColor(const QColor& /*color*/) +{ +} + +Qt::Qt::BGMode KisOpenGLCanvasPainter::backgroundMode() const +{ + return Qt::TransparentMode; +} + +void KisOpenGLCanvasPainter::setBackgroundMode(Qt::Qt::BGMode /*bgMode*/) +{ +} + +Qt::Qt::RasterOp KisOpenGLCanvasPainter::rasterOp() const +{ + return Qt::CopyROP; +} + +void KisOpenGLCanvasPainter::setRasterOp(Qt::RasterOp /*rasterOp*/) +{ +} + +const QPoint& KisOpenGLCanvasPainter::brushOrigin() const +{ + return m_defaultBrushOrigin; +} + +void KisOpenGLCanvasPainter::setBrushOrigin(int /*x*/, int /*y*/) +{ +} + +void KisOpenGLCanvasPainter::setBrushOrigin(const QPoint& /*origin*/) +{ +} + +bool KisOpenGLCanvasPainter::hasViewXForm() const +{ + return false; +} + +bool KisOpenGLCanvasPainter::hasWorldXForm() const +{ + return false; +} + +void KisOpenGLCanvasPainter::setViewXForm(bool /*enable*/) +{ +} + +QRect KisOpenGLCanvasPainter::window() const +{ + return m_window; +} + +void KisOpenGLCanvasPainter::setWindow(const QRect& r) +{ + m_window = r; + updateViewTransformation(); +} + +void KisOpenGLCanvasPainter::setWindow(int x, int y, int w, int h) +{ + setWindow(QRect(x, y, w, h)); +} + +QRect KisOpenGLCanvasPainter::viewport() const +{ + return m_viewport; +} + +void KisOpenGLCanvasPainter::setViewport(const QRect& r) +{ + m_viewport = r; + updateViewTransformation(); +} + +void KisOpenGLCanvasPainter::setViewport(int x, int y, int w, int h) +{ + setViewport(QRect(x, y, w, h)); +} + +void KisOpenGLCanvasPainter::setWorldXForm(bool /*enable*/) +{ +} + +const QWMatrix& KisOpenGLCanvasPainter::worldMatrix() const +{ + return m_defaultWorldMatrix; +} + +void KisOpenGLCanvasPainter::setWorldMatrix(const QWMatrix& /*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; +} + +QPoint KisOpenGLCanvasPainter::xForm(const QPoint& point) const +{ + return point; +} + +QRect KisOpenGLCanvasPainter::xForm(const QRect& r) const +{ + return r; +} + +QPointArray KisOpenGLCanvasPainter::xForm(const QPointArray& pointArray) const +{ + return pointArray; +} + +QPointArray KisOpenGLCanvasPainter::xForm(const QPointArray& pointArray, int /*index*/, int /*npoints*/) const +{ + return pointArray; +} + +QPoint KisOpenGLCanvasPainter::xFormDev(const QPoint& point) const +{ + return point; +} + +QRect KisOpenGLCanvasPainter::xFormDev(const QRect& r) const +{ + return r; +} + +QPointArray KisOpenGLCanvasPainter::xFormDev(const QPointArray& pointArray) const +{ + return pointArray; +} + +QPointArray KisOpenGLCanvasPainter::xFormDev(const QPointArray& pointArray, int /*index*/, int /*npoints*/) const +{ + return pointArray; +} + +void KisOpenGLCanvasPainter::setClipping(bool /*enable*/) +{ +} + +bool KisOpenGLCanvasPainter::hasClipping() const +{ + return true; +} + +QRegion KisOpenGLCanvasPainter::clipRegion(QPainter::CoordinateMode /*mode*/) const +{ + return QRegion(); +} + +void KisOpenGLCanvasPainter::setClipRect(const QRect& /*r*/, QPainter::CoordinateMode /*mode*/) +{ +} + +void KisOpenGLCanvasPainter::setClipRect(int /*x*/, int /*y*/, int /*w*/, int /*h*/, QPainter::CoordinateMode /*mode*/) +{ +} + +void KisOpenGLCanvasPainter::setClipRegion(const QRegion& /*rgn*/, QPainter::CoordinateMode /*mode*/) +{ +} + +void KisOpenGLCanvasPainter::drawPoint(int x, int y) +{ + glBegin(GL_POINTS); + glVertex2i(x, y); + glEnd(); +} + +void KisOpenGLCanvasPainter::drawPoint(const QPoint& point) +{ + drawPoint(point.x(), point.y()); +} + +void KisOpenGLCanvasPainter::drawPoints(const QPointArray& 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++) { + QPoint point = pointArray.point(pointIndex); + glVertex2i(point.x(), point.y()); + } + + glEnd(); +} + +void KisOpenGLCanvasPainter::moveTo(int /*x*/, int /*y*/) +{ +} + +void KisOpenGLCanvasPainter::moveTo(const QPoint& /*point*/) +{ +} + +void KisOpenGLCanvasPainter::lineTo(int /*x*/, int /*y*/) +{ +} + +void KisOpenGLCanvasPainter::lineTo(const QPoint& /*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 QPoint& start, const QPoint& 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 QRect& 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 QColor& /*bgColor*/) +{ +} + +void KisOpenGLCanvasPainter::drawWinFocusRect(const QRect& /*r*/) +{ +} + +void KisOpenGLCanvasPainter::drawWinFocusRect(const QRect& /*r*/, const QColor& /*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 QRect& 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 QRect& /*r*/, int /*xRnd*/, int /*yRnd*/) +// { +// } + +void KisOpenGLCanvasPainter::drawEllipse(int x, int y, int w, int h) +{ + QRect r(x, y, w, h); + r = r.normalize(); + + QPointArray points; + + points.makeEllipse(r.x(), r.y(), r.width(), r.height()); + drawPoints(points); +} + +void KisOpenGLCanvasPainter::drawEllipse(const QRect& 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 QRect& /*r*/, int /*a*/, int /*alen*/) +{ +} + +void KisOpenGLCanvasPainter::drawPie(int /*x*/, int /*y*/, int /*w*/, int /*h*/, int /*a*/, int /*alen*/) +{ +} + +void KisOpenGLCanvasPainter::drawPie(const QRect& /*r*/, int /*a*/, int /*alen*/) +{ +} + +void KisOpenGLCanvasPainter::drawChord(int /*x*/, int /*y*/, int /*w*/, int /*h*/, int /*a*/, int /*alen*/) +{ +} + +void KisOpenGLCanvasPainter::drawChord(const QRect& /*r*/, int /*a*/, int /*alen*/) +{ +} + +void KisOpenGLCanvasPainter::drawLineSegments(const QPointArray& /*pointArray*/, int /*index*/, int /*nlines*/) +{ +} + +void KisOpenGLCanvasPainter::drawPolyline(const QPointArray& 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++) { + QPoint point = pointArray.point(pointIndex); + glVertex2i(point.x(), point.y()); + } + + glEnd(); +} + +void KisOpenGLCanvasPainter::drawPolygon(const QPointArray& /*pointArray*/, bool /*winding*/, int /*index*/, int /*npoints*/) +{ +} + +void KisOpenGLCanvasPainter::drawConvexPolygon(const QPointArray& /*pointArray*/, int /*index*/, int /*npoints*/) +{ +} + +QPoint midpoint (const QPoint& P1, const QPoint& P2) +{ + QPoint temp; + temp.setX((P1.x()+P2.x())/2); + temp.setY((P1.y()+P2.y())/2); + return temp; +} + +#define MAX_LEVEL 5 + +void recursiveCurve (const QPoint& P1, const QPoint& P2, const QPoint& P3, + const QPoint& P4, int level, QValueList& dest) +{ + if (level > MAX_LEVEL) { + dest.append(midpoint(P1,P4)); + return; + } + + QPoint L1, L2, L3, L4; + QPoint 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 QPointArray& pointArray, int index) +{ + QPoint P1, P2, P3, P4; + QValueList 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 (QValueList::iterator it = dest.begin(); it != dest.end(); it++) { + QPoint point = (*it); + glVertex2i(point.x(), point.y()); + } + glVertex2i(P4.x(), P4.y()); + + glEnd(); +} + +void KisOpenGLCanvasPainter::drawPixmap(int /*x*/, int /*y*/, const QPixmap& /*pixmap*/, int /*sx*/, int /*sy*/, int /*sw*/, int /*sh*/) +{ +} + +void KisOpenGLCanvasPainter::drawPixmap(const QPoint& /*point*/, const QPixmap& /*pixmap*/, const QRect& /*sr*/) +{ +} + +void KisOpenGLCanvasPainter::drawPixmap(const QPoint& /*point*/, const QPixmap& /*pixmap*/) +{ +} + +void KisOpenGLCanvasPainter::drawPixmap(const QRect& /*r*/, const QPixmap& /*pixmap*/) +{ +} + +void KisOpenGLCanvasPainter::drawImage(int /*x*/, int /*y*/, const QImage& /*image*/, int /*sx*/, int /*sy*/, int /*sw*/, int /*sh*/, int /*conversionFlags*/) +{ +} + +void KisOpenGLCanvasPainter::drawImage(const QPoint& /*point*/, const QImage& /*image*/, const QRect& /*sr*/, int /*conversionFlags*/) +{ +} + +void KisOpenGLCanvasPainter::drawImage(const QPoint& /*point*/, const QImage& /*image*/, int /*conversion_flags*/) +{ +} + +void KisOpenGLCanvasPainter::drawImage(const QRect& /*r*/, const QImage& /*image*/) +{ +} + +void KisOpenGLCanvasPainter::drawTiledPixmap(int /*x*/, int /*y*/, int /*w*/, int /*h*/, const QPixmap& /*pixmap*/, int /*sx*/, int /*sy*/) +{ +} + +void KisOpenGLCanvasPainter::drawTiledPixmap(const QRect& /*r*/, const QPixmap& /*pixmap*/, const QPoint& /*point*/) +{ +} + +void KisOpenGLCanvasPainter::drawTiledPixmap(const QRect& /*r*/, const QPixmap& /*pixmap*/) +{ +} + +void KisOpenGLCanvasPainter::fillRect(int x, int y, int w, int h, const QBrush& /*brush*/) +{ + // XXX: Set brush + glRecti(x, y, x + w, y + h); +} + +void KisOpenGLCanvasPainter::fillRect(const QRect& r, const QBrush& 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 QRect& /*r*/) +{ +} + +void KisOpenGLCanvasPainter::drawText(int /*x*/, int /*y*/, const QString& /*text*/, int /*len*/, QPainter::TextDirection /*dir*/) +{ +} + +void KisOpenGLCanvasPainter::drawText(const QPoint& /*point*/, const QString& /*text*/, int /*len*/, QPainter::TextDirection /*dir*/) +{ +} + +void KisOpenGLCanvasPainter::drawText(int /*x*/, int /*y*/, const QString& /*text*/, int /*pos*/, int /*len*/, QPainter::TextDirection /*dir*/) +{ +} + +void KisOpenGLCanvasPainter::drawText(const QPoint& /*point*/, const QString& /*text*/, int /*pos*/, int /*len*/, QPainter::TextDirection /*dir*/) +{ +} + +void KisOpenGLCanvasPainter::drawText(int /*x*/, int /*y*/, int /*w*/, int /*h*/, int /*flags*/, const QString& /*text*/, int /*len*/, QRect */*br*/, QTextParag **/*intern*/) +{ +} + +void KisOpenGLCanvasPainter::drawText(const QRect& /*r*/, int /*flags*/, const QString& /*text*/, int /*len*/, QRect */*br*/, QTextParag **/*intern*/) +{ +} + +void KisOpenGLCanvasPainter::drawTextItem(int /*x*/, int /*y*/, const QTextItem& /*ti*/, int /*textflags*/) +{ +} + +void KisOpenGLCanvasPainter::drawTextItem(const QPoint& /*p*/, const QTextItem& /*ti*/, int /*textflags*/) +{ +} + +QRect KisOpenGLCanvasPainter::boundingRect(int /*x*/, int /*y*/, int /*w*/, int /*h*/, int /*flags*/, const QString& /*text*/, int /*len*/, QTextParag **/*intern*/) +{ + return QRect(); +} + +QRect KisOpenGLCanvasPainter::boundingRect(const QRect& /*r*/, int /*flags*/, const QString& /*text*/, int /*len*/, QTextParag **/*intern*/) +{ + return QRect(); +} + +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/krita/ui/kis_opengl_canvas_painter.h b/krita/ui/kis_opengl_canvas_painter.h new file mode 100644 index 00000000..7f129947 --- /dev/null +++ b/krita/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(QGLWidget *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 QFontMetrics fontMetrics() const; + virtual QFontInfo fontInfo() const; + + virtual const QFont& font() const; + virtual void setFont(const QFont&); + virtual const QPen& pen() const; + virtual void setPen(const QPen&); + virtual void setPen(Qt::PenStyle); + virtual void setPen(const QColor&); + virtual const QBrush&brush() const; + virtual void setBrush(const QBrush&); + virtual void setBrush(Qt::BrushStyle); + virtual void setBrush(const QColor&); + virtual QPoint pos() const; + + virtual const QColor& backgroundColor() const; + virtual void setBackgroundColor(const QColor&); + virtual Qt::BGMode backgroundMode() const; + virtual void setBackgroundMode(Qt::BGMode); + virtual Qt::RasterOp rasterOp() const; + virtual void setRasterOp(Qt::RasterOp); + virtual const QPoint& brushOrigin() const; + virtual void setBrushOrigin(int x, int y); + virtual void setBrushOrigin(const QPoint&); + + virtual bool hasViewXForm() const; + virtual bool hasWorldXForm() const; + + virtual void setViewXForm(bool); + virtual QRect window() const; + virtual void setWindow(const QRect&); + virtual void setWindow(int x, int y, int w, int h); + virtual QRect viewport() const; + virtual void setViewport(const QRect&); + virtual void setViewport(int x, int y, int w, int h); + + virtual void setWorldXForm(bool); + virtual const QWMatrix&worldMatrix() const; + virtual void setWorldMatrix(const QWMatrix&, 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 QPoint xForm(const QPoint&) const; + virtual QRect xForm(const QRect&) const; + virtual QPointArray xForm(const QPointArray&) const; + virtual QPointArray xForm(const QPointArray&, int index, int npoints) const; + virtual QPoint xFormDev(const QPoint&) const; + virtual QRect xFormDev(const QRect&) const; + virtual QPointArray xFormDev(const QPointArray&) const; + virtual QPointArray xFormDev(const QPointArray&, int index, int npoints) const; + + virtual void setClipping(bool); + virtual bool hasClipping() const; + virtual QRegion clipRegion(QPainter::CoordinateMode = QPainter::CoordDevice) const; + virtual void setClipRect(const QRect&, QPainter::CoordinateMode = QPainter::CoordDevice); + virtual void setClipRect(int x, int y, int w, int h, QPainter::CoordinateMode = QPainter::CoordDevice); + virtual void setClipRegion(const QRegion&, QPainter::CoordinateMode = QPainter::CoordDevice); + + virtual void drawPoint(int x, int y); + virtual void drawPoint(const QPoint&); + virtual void drawPoints(const QPointArray& a, int index=0, int npoints=-1); + virtual void moveTo(int x, int y); + virtual void moveTo(const QPoint&); + virtual void lineTo(int x, int y); + virtual void lineTo(const QPoint&); + virtual void drawLine(int x1, int y1, int x2, int y2); + virtual void drawLine(const QPoint&, const QPoint&); + virtual void drawRect(int x, int y, int w, int h); + virtual void drawRect(const QRect&); + virtual void drawWinFocusRect(int x, int y, int w, int h); + virtual void drawWinFocusRect(int x, int y, int w, int h, const QColor&bgColor); + virtual void drawWinFocusRect(const QRect&); + virtual void drawWinFocusRect(const QRect&, const QColor&bgColor); + virtual void drawRoundRect(int x, int y, int w, int h, int = 25, int = 25); + virtual void drawRoundRect(const QRect&, int = 25, int = 25); + virtual void drawEllipse(int x, int y, int w, int h); + virtual void drawEllipse(const QRect&); + virtual void drawArc(int x, int y, int w, int h, int a, int alen); + virtual void drawArc(const QRect&, int a, int alen); + virtual void drawPie(int x, int y, int w, int h, int a, int alen); + virtual void drawPie(const QRect&, int a, int alen); + virtual void drawChord(int x, int y, int w, int h, int a, int alen); + virtual void drawChord(const QRect&, int a, int alen); + virtual void drawLineSegments(const QPointArray&, int index=0, int nlines=-1); + virtual void drawPolyline(const QPointArray&, int index=0, int npoints=-1); + virtual void drawPolygon(const QPointArray&, bool winding=FALSE, int index=0, int npoints=-1); + virtual void drawConvexPolygon(const QPointArray&, int index=0, int npoints=-1); + virtual void drawCubicBezier(const QPointArray&, int index=0); + virtual void drawPixmap(int x, int y, const QPixmap&, int sx=0, int sy=0, int sw=-1, int sh=-1); + virtual void drawPixmap(const QPoint&, const QPixmap&, const QRect&sr); + virtual void drawPixmap(const QPoint&, const QPixmap&); + virtual void drawPixmap(const QRect&, const QPixmap&); + virtual void drawImage(int x, int y, const QImage&, int sx = 0, int sy = 0, int sw = -1, int sh = -1, int conversionFlags = 0); + virtual void drawImage(const QPoint&, const QImage&, const QRect&sr, int conversionFlags = 0); + virtual void drawImage(const QPoint&, const QImage&, int conversion_flags = 0); + virtual void drawImage(const QRect&, const QImage&); + virtual void drawTiledPixmap(int x, int y, int w, int h, const QPixmap&, int sx=0, int sy=0); + virtual void drawTiledPixmap(const QRect&, const QPixmap&, const QPoint&); + virtual void drawTiledPixmap(const QRect&, const QPixmap&); + //virtual void drawPicture(const QPicture&); + //virtual void drawPicture(int x, int y, const QPicture&); + //virtual void drawPicture(const QPoint&, const QPicture&); + + virtual void fillRect(int x, int y, int w, int h, const QBrush&); + virtual void fillRect(const QRect&, const QBrush&); + virtual void eraseRect(int x, int y, int w, int h); + virtual void eraseRect(const QRect&); + + virtual void drawText(int x, int y, const QString&, int len = -1, QPainter::TextDirection dir = QPainter::Auto); + virtual void drawText(const QPoint&, const QString&, int len = -1, QPainter::TextDirection dir = QPainter::Auto); + + virtual void drawText(int x, int y, const QString&, int pos, int len, QPainter::TextDirection dir = QPainter::Auto); + virtual void drawText(const QPoint&p, const QString&, int pos, int len, QPainter::TextDirection dir = QPainter::Auto); + + virtual void drawText(int x, int y, int w, int h, int flags, const QString&, int len = -1, QRect *br=0, QTextParag **intern=0); + virtual void drawText(const QRect&, int flags, const QString&, int len = -1, QRect *br=0, QTextParag **intern=0); + + virtual void drawTextItem(int x, int y, const QTextItem&ti, int textflags = 0); + virtual void drawTextItem(const QPoint& p, const QTextItem&ti, int textflags = 0); + + virtual QRect boundingRect(int x, int y, int w, int h, int flags, const QString&, int len = -1, QTextParag **intern=0); + virtual QRect boundingRect(const QRect&, int flags, const QString&, int len = -1, QTextParag **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: + QFont m_defaultFont; + QPen m_defaultPen; + QBrush m_defaultBrush; + QColor m_defaultColor; + QPoint m_defaultBrushOrigin; + QWMatrix m_defaultWorldMatrix; + QRect m_window; + QRect m_viewport; + bool m_active; + +protected: + QGLWidget *m_widget; +}; + +#endif // HAVE_GL + +#endif // KIS_OPENGL_CANVAS_PAINTER_H_ + diff --git a/krita/ui/kis_opengl_image_context.cc b/krita/ui/kis_opengl_image_context.cc new file mode 100644 index 00000000..f3ad4341 --- /dev/null +++ b/krita/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; + +QGLWidget *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 QGLWidget(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 = QMIN(PREFERRED_IMAGE_TEXTURE_WIDTH, max_texture_size); + m_imageTextureTileHeight = QMIN(PREFERRED_IMAGE_TEXTURE_HEIGHT, max_texture_size); + + createImageTextureTiles(); + + connect(m_image, SIGNAL(sigImageUpdated(QRect)), + SLOT(slotImageUpdated(QRect))); + connect(m_image, SIGNAL(sigSizeChanged(Q_INT32, Q_INT32)), + SLOT(slotImageSizeChanged(Q_INT32, Q_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; + } +} + +QGLWidget *KisOpenGLImageContext::sharedContextWidget() const +{ + return SharedContextWidget; +} + +void KisOpenGLImageContext::updateImageTextureTiles(const QRect& rect) +{ + //kdDebug() << "updateImageTextureTiles " << rect << endl; + + QRect 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++) { + + QRect tileRect(column * m_imageTextureTileWidth, row * m_imageTextureTileHeight, + m_imageTextureTileWidth, m_imageTextureTileHeight); + + QRect 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); + + QImage tileUpdateImage = m_image->convertToQImage(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); + + QImage 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 +{ + Q_INT32 textureTileIndex = imageTextureTileIndex(pixelX, pixelY); + + textureTileIndex = CLAMP(textureTileIndex, 0, ((Q_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 + + QByteArray 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 QRect& imageRect) +{ + updateImageTextureTiles(imageRect); +} + +void KisOpenGLImageContext::setSelectionDisplayEnabled(bool enable) +{ + m_displaySelection = enable; +} + +void KisOpenGLImageContext::slotImageUpdated(QRect rc) +{ + QRect r = rc & m_image->bounds(); + + updateImageTextureTiles(r); + emit sigImageUpdated(r); +} + +void KisOpenGLImageContext::slotImageSizeChanged(Q_INT32 w, Q_INT32 h) +{ + createImageTextureTiles(); + updateImageTextureTiles(m_image->bounds()); + + emit sigSizeChanged(w, h); +} + +#include "kis_opengl_image_context.moc" + +#endif // HAVE_GL + diff --git a/krita/ui/kis_opengl_image_context.h b/krita/ui/kis_opengl_image_context.h new file mode 100644 index 00000000..d1ba6278 --- /dev/null +++ b/krita/ui/kis_opengl_image_context.h @@ -0,0 +1,156 @@ +/* + * 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 QRegion; + +class KisOpenGLImageContext; +typedef KSharedPtr KisOpenGLImageContextSP; +class KisColorSpace; + +class KRITACORE_EXPORT KisOpenGLImageContext : public QObject , public KShared { + + Q_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 + // QGLWidget constructor. + QGLWidget *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 QRect& 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(QRect rc); + + /** + * Emitted whenever the image size changes. + * + * @param width New image width + * @param height New image height + */ + void sigSizeChanged(Q_INT32 width, Q_INT32 height); + +protected: + KisOpenGLImageContext(KisImageSP image, KisProfile *monitorProfile); + + void generateBackgroundTexture(); + void createImageTextureTiles(); + void destroyImageTextureTiles(); + int imageTextureTileIndex(int x, int y) const; + void updateImageTextureTiles(const QRect& rect); + + static KisColorSpace* textureColorSpaceForImageColorSpace(KisColorSpace *imageColorSpace); + static bool imageCanShareImageContext(KisImageSP image); + +protected slots: + void slotImageUpdated(QRect r); + void slotImageSizeChanged(Q_INT32 w, Q_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; + + QValueVector 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. Apparently with some OpenGL implementations, only + // one context will be hardware accelerated. + static QGLWidget *SharedContextWidget; + static int SharedContextWidgetRefCount; + + typedef std::map ImageContextMap; + + static ImageContextMap imageContextMap; +}; + +#endif // HAVE_GL + +#endif // KIS_OPENGL_IMAGE_CONTEXT_H_ + diff --git a/krita/ui/kis_paintop_box.cc b/krita/ui/kis_paintop_box.cc new file mode 100644 index 00000000..3479075d --- /dev/null +++ b/krita/ui/kis_paintop_box.cc @@ -0,0 +1,249 @@ +/* + * kis_paintop_box.cc - part of KImageShop/Krayon/Krita + * + * 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, QWidget *parent, const char * name) + : super (parent, 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 QValueList(); + m_displayedOps = new QValueList(); + + m_cmbPaintops = new QComboBox(this, "KisPaintopBox::m_cmbPaintops"); + m_cmbPaintops->setMinimumWidth(150); + QToolTip::add(m_cmbPaintops, i18n("Styles of painting for the painting tools")); + m_layout = new QHBoxLayout(this, 1, 1); + m_layout->addWidget(m_cmbPaintops); + + connect(this, SIGNAL(selected(const KisID &, const KisPaintOpSettings *)), view, SLOT(paintopActivated(const KisID &, const KisPaintOpSettings *))); + connect(m_cmbPaintops, SIGNAL(activated(int)), this, 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, SIGNAL(currentColorSpaceChanged(KisColorSpace*)), + this, SLOT(colorSpaceChanged(KisColorSpace*))); + connect(view, SIGNAL(sigInputDeviceChanged(const KisInputDevice&)), + this, SLOT(slotInputDeviceChanged(const KisInputDevice&))); + + setCurrentPaintop(defaultPaintop(m_canvasController->currentInputDevice())); +} + +KisPaintopBox::~KisPaintopBox() +{ + delete m_paintops; + delete m_displayedOps; +} + +void KisPaintopBox::addItem(const KisID & paintop, const QString & /*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) +{ + QValueList::iterator it = m_paintops->begin(); + QValueList::iterator end = m_paintops->end(); + m_displayedOps->clear(); + m_cmbPaintops->clear(); + + for ( ; it != end; ++it ) { + if (KisPaintOpRegistry::instance()->userVisible(*it, cs)) { + QPixmap pm = paintopPixmap(*it); + if (pm.isNull()) { + QPixmap p = QPixmap( 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->findIndex(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 ); +} + +QPixmap KisPaintopBox::paintopPixmap(const KisID & paintop) +{ + QString pixmapName = KisPaintOpRegistry::instance()->pixmap(paintop); + + if (pixmapName.isEmpty()) { + return QPixmap(); + } + + QString fname = KisFactory::instance()->dirs()->findResource("kis_images", pixmapName); + + return QPixmap(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->findIndex(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->invalidate(); + } + + 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) +{ + QValueVector settingsArray; + InputDevicePaintopSettingsMap::iterator it = m_inputDevicePaintopSettings.find(inputDevice); + + if (it == m_inputDevicePaintopSettings.end()) { + // Create settings for each paintop. + + for (QValueList::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->findIndex(paintop); + if (index >= 0 && index < (int)settingsArray.count()) + return settingsArray[index]; + else + return 0; +} + +#include "kis_paintop_box.moc" + diff --git a/krita/ui/kis_paintop_box.h b/krita/ui/kis_paintop_box.h new file mode 100644 index 00000000..da158194 --- /dev/null +++ b/krita/ui/kis_paintop_box.h @@ -0,0 +1,103 @@ +/* + * kis_paintop_box.h - part of KImageShop/Krayon/Krita + * + * 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 QString; + +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 QWidget { + + Q_OBJECT + + typedef QWidget super; + +public: + KisPaintopBox (KisView * view, QWidget * parent, const char * name = 0); + + ~KisPaintopBox(); + + +signals: + + void selected(const KisID & id, const KisPaintOpSettings *settings); + +private slots: + + void addItem(const KisID & paintop, const QString & category = ""); + +private slots: + + void slotItemSelected(int index); + void colorSpaceChanged(KisColorSpace *cs); + void slotInputDeviceChanged(const KisInputDevice & inputDevice); + +private: + QPixmap 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; + QComboBox * m_cmbPaintops; + QHBoxLayout * m_layout; + QWidget * m_optionWidget; + + QValueList * m_paintops; + QValueList * m_displayedOps; + + typedef std::map InputDevicePaintopMap; + InputDevicePaintopMap m_currentID; + + typedef std::map > InputDevicePaintopSettingsMap; + InputDevicePaintopSettingsMap m_inputDevicePaintopSettings; +}; + + + +#endif //KIS_PAINTOP_BOX_H_ + diff --git a/krita/ui/kis_palette_view.cc b/krita/ui/kis_palette_view.cc new file mode 100644 index 00000000..2fe3f6e9 --- /dev/null +++ b/krita/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(QWidget *parent, const char* name, int minWidth, int cols) + : QScrollView( parent, name ), mMinWidth(minWidth), mCols(cols) +{ + m_cells = 0; + m_currentPalette = 0; + + QSize cellSize = QSize( mMinWidth, 50); + + setHScrollBarMode(QScrollView::AlwaysOff); + setVScrollBarMode(QScrollView::AlwaysOn); + + QSize minSize = QSize(verticalScrollBar()->width(), 0); + minSize += QSize(frameWidth(), 0); + minSize += QSize(cellSize); + + setMinimumSize(minSize); + setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::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); + + QSize cellSize = QSize( mMinWidth, mMinWidth * rows / mCols); + m_cells->setFixedSize( cellSize ); + + for( int i = 0; i < m_currentPalette->nColors(); i++) + { + QColor c = m_currentPalette->getColor(i).color; + m_cells->setColor( i, c ); + } + + connect(m_cells, SIGNAL(colorSelected(int)), + SLOT(slotColorCellSelected(int))); + + connect(m_cells, SIGNAL(colorDoubleClicked(int)), + 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/krita/ui/kis_palette_view.h b/krita/ui/kis_palette_view.h new file mode 100644 index 00000000..8812acdb --- /dev/null +++ b/krita/ui/kis_palette_view.h @@ -0,0 +1,69 @@ +/* + * 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 QScrollView +{ + Q_OBJECT +public: + KisPaletteView(QWidget *parent, 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 QColor &); + void colorDoubleClicked(const KisColor &, const QString &); + +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/krita/ui/kis_palette_widget.cc b/krita/ui/kis_palette_widget.cc new file mode 100644 index 00000000..507ccc15 --- /dev/null +++ b/krita/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( QWidget *parent, int minWidth, int cols) + : QWidget( parent ), mMinWidth(minWidth), mCols(cols) +{ + init = false; + + m_currentPalette = 0; + + QVBoxLayout *layout = new QVBoxLayout( this ); + + combo = new QComboBox( false, this ); + combo->setFocusPolicy( QWidget::ClickFocus ); + layout->addWidget(combo); + + m_view = new KisPaletteView(this, 0, minWidth, cols); + layout->addWidget( m_view ); + + //setFixedSize(sizeHint()); + + connect(combo, SIGNAL(activated(const QString &)), + this, SLOT(slotSetPalette(const QString &))); + connect(m_view, SIGNAL(colorSelected(const KisColor &)), + this, SIGNAL(colorSelected(const KisColor &))); + connect(m_view, SIGNAL(colorSelected(const QColor &)), + this, SIGNAL(colorSelected(const QColor &))); + connect(m_view, SIGNAL(colorDoubleClicked(const KisColor &, const QString &)), + this, SIGNAL(colorDoubleClicked(const KisColor &, const QString &))); +} + +KisPaletteWidget::~KisPaletteWidget() +{ +} + +QString 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 QString &_paletteName ) +{ + setPalette( _paletteName ); + m_view->slotColorCellSelected(0); // FIXME: We need to save the current value!! +} + + +void KisPaletteWidget::setPalette( const QString &_paletteName ) +{ + QString 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/krita/ui/kis_palette_widget.h b/krita/ui/kis_palette_widget.h new file mode 100644 index 00000000..bdfa8cdf --- /dev/null +++ b/krita/ui/kis_palette_widget.h @@ -0,0 +1,79 @@ +/* + * 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 QComboBox; +class QLineEdit; +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 QWidget +{ + Q_OBJECT +public: + KisPaletteWidget( QWidget *parent, int minWidth=210, int cols = 16); + virtual ~KisPaletteWidget(); + + QString palette() const; + KisPaletteEntry currentEntry() const { return m_view->currentEntry(); } + +public slots: + void setPalette(const QString &paletteName); + +signals: + void colorSelected(const KisColor &); + void colorSelected(const QColor&); + void colorDoubleClicked( const KisColor &, const QString &); + +protected slots: + void slotSetPalette( const QString &_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; + QDict m_namedPaletteMap; + KisPalette * m_currentPalette; + QComboBox *combo; + QScrollView *sv; + int mMinWidth; + int mCols; + bool init; +}; + +#endif + diff --git a/krita/ui/kis_part_layer.cc b/krita/ui/kis_part_layer.cc new file mode 100644 index 00000000..f34f6ebc --- /dev/null +++ b/krita/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 "qpaintdevice.h" +#include "qpixmap.h" +#include "qimage.h" +#include "qpainter.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 QRect & 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 QObject, and krita 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) { + QRect rect = extent(); + m_activated = true; + setDirty(rect); + QPtrList views = child->parentDocument()->views(); + Q_ASSERT(views.count()); + // XXX iterate over views + connect(views.at(0), SIGNAL(activated(bool)), + this, 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 repaint where we currently updated + // We use the original geometry + if (m_activated && !activated /* no clue, but debugging suggests it is false here */) { + QPtrList views = m_doc->parentDocument()->views(); + Q_ASSERT(views.count()); + views.at(0)->disconnect(SIGNAL(activated(bool))); + m_activated = false; + setDirty(m_doc->geometry()); + } +} + +void KisPartLayerImpl::setX(Q_INT32 x) { + QRect rect = m_doc->geometry(); + + // 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(Q_INT32 y) { + QRect rect = m_doc->geometry(); + + // 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(QImage &img, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h) { + uchar *j = img.bits(); + QRect rect = m_doc->geometry(); + + for (int y2 = y; y2 < h + y; ++y2) { + for (int x2 = x; x2 < w + x; ++x2) { + if (!rect.contains(x2, y2)) { + Q_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 QRect& r) +{ + if (!m_doc || !m_doc->document() || m_activated) return 0; + + m_cache->clear(); + + QRect 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. + QRect embedRect(intersection); + embedRect.moveBy(- exactBounds().x(), - exactBounds().y()); + QRect paintRect(exactBounds()); + paintRect.moveBy(- exactBounds().x(), - exactBounds().y()); + + QPixmap pm1(projection->convertToQImage(0 /*srgb XXX*/, + intersection.x(), intersection.y(), + intersection.width(), intersection.height())); + QPixmap pm2(extent().width(), extent().height()); + copyBlt(&pm2, embedRect.x(), embedRect.y(), &pm1, + 0, 0, embedRect.width(), embedRect.height()); + QPainter painter(&pm2); + painter.setClipRect(embedRect); + + // KWord's KWPartFrameSet::drawFrameContents has some interesting remarks concerning + // the semantics of the paintEverything call. + // Since a Krita 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()); + QImage qimg = pm1.convertToImage(); + + //assume the part is sRGB for now, and that "" is sRGB + // And we need to paint offsetted + m_cache->convertFromQImage(qimg, "", intersection.left(), intersection.top()); + + return m_cache; +} + +QImage KisPartLayerImpl::createThumbnail(Q_INT32 w, Q_INT32 h) { + QRect bounds(exactBounds()); + QPixmap pm(w, h); + QPainter painter(&pm); + + painter.fillRect(0, 0, w, h, Qt::white); + + painter.scale(w / bounds.width(), h / bounds.height()); + m_doc->document()->paintEverything(painter, bounds); + QImage qimg = pm.convertToImage(); + + return qimg; +} + +bool KisPartLayerImpl::saveToXML(QDomDocument doc, QDomElement elem) +{ + QDomElement 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); + + QDomElement 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) { + QObject::connect(m_view, SIGNAL(childActivated(KoDocumentChild*)), + layer, SLOT(childActivated(KoDocumentChild*))); + } else { + QObject::disconnect(m_view, 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/krita/ui/kis_part_layer.h b/krita/ui/kis_part_layer.h new file mode 100644 index 00000000..efe57c28 --- /dev/null +++ b/krita/ui/kis_part_layer.h @@ -0,0 +1,147 @@ +/* + * 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 QRect& rect, KoDocument * childDoc ); + KisChildDoc ( KisDoc * kisDdoc ); + + virtual ~KisChildDoc(); + + KisDoc * parent() 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 Krita Fileformat natively. + */ +class KisPartLayerImpl : public KisPartLayer { + Q_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 QString& type) { m_docType = type; } + QString docType() const { return m_docType; } + + virtual void setX(Q_INT32 x); + virtual void setY(Q_INT32 y); + virtual Q_INT32 x() const { return m_doc->geometry() . x(); } + virtual Q_INT32 y() const { return m_doc->geometry() . y(); } //m_paintLayer->y(); } + virtual QRect extent() const { return m_doc->geometry(); } + virtual QRect exactBounds() const { return m_doc->geometry(); } + + virtual QImage createThumbnail(Q_INT32 w, Q_INT32 h); + + virtual bool accept(KisLayerVisitor& visitor) { + return visitor.visit(this); + } + + virtual KisPaintDeviceSP prepareProjection(KisPaintDeviceSP projection, const QRect& r); + + virtual void paintSelection(QImage &img, Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h); + + virtual bool saveToXML(QDomDocument doc, QDomElement elem); +private slots: + /// Repaints our device with the data from the embedded part + //void repaint(); + /// 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 + QString 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/krita/ui/kis_part_layer_handler.cc b/krita/ui/kis_part_layer_handler.cc new file mode 100644 index 00000000..787de872 --- /dev/null +++ b/krita/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 parent, KisLayerSP above) + : m_parent(parent), 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 + QRect r(m_start, m_end); + r = r.normalize(); + if (!r.isEmpty()) + painter.drawRect(r); + + m_end = event->pos().roundQPoint(); + r = QRect(m_start, m_end).normalize(); + + painter.drawRect(r); + painter.end(); +} + +void KisPartLayerHandler::gotButtonPressEvent(KisButtonPressEvent* event) { + m_start = event->pos().roundQPoint(); + m_end = m_start; + m_started = true; +} + +void KisPartLayerHandler::gotButtonReleaseEvent(KisButtonReleaseEvent* event) { + if (!m_started) { + done(); + return; + } + + m_end = event->pos().roundQPoint(); + + QRect 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(QKeyEvent* event) { + if (event->key() == Key_Escape) { + done(); + } else { + emit sigGotKeyPressEvent(event); + } +} + +#include "kis_part_layer_handler.moc" diff --git a/krita/ui/kis_part_layer_handler.h b/krita/ui/kis_part_layer_handler.h new file mode 100644 index 00000000..7b6d3f0b --- /dev/null +++ b/krita/ui/kis_part_layer_handler.h @@ -0,0 +1,57 @@ +/* + * 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 QKeyEvent; + +class KisPartLayerHandler : public QObject { +Q_OBJECT +public: + KisPartLayerHandler(KisView* view, const KoDocumentEntry& entry, + KisGroupLayerSP parent, KisLayerSP above); +signals: + void sigGotMoveEvent(KisMoveEvent* event); + void sigGotKeyPressEvent(QKeyEvent* event); + void handlerDone(); + +protected slots: + + void gotMoveEvent(KisMoveEvent* event); + void gotButtonPressEvent(KisButtonPressEvent* event); + void gotButtonReleaseEvent(KisButtonReleaseEvent* event); + void gotKeyPressEvent(QKeyEvent* event); +protected: + void done(); + KisGroupLayerSP m_parent; + KisLayerSP m_above; + KisView* m_view; + KoDocumentEntry m_entry; + QPoint m_start; + QPoint m_end; + bool m_started; +}; + +#endif // KIS_PART_LAYER_HANDLER diff --git a/krita/ui/kis_pattern_chooser.cc b/krita/ui/kis_pattern_chooser.cc new file mode 100644 index 00000000..8a9d08b0 --- /dev/null +++ b/krita/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(QWidget *parent, const char *name) : super(parent, name) +{ + m_lbName = new QLabel(this); + + QVBoxLayout *mainLayout = new QVBoxLayout(this, 2, -1, "main layout"); + + 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()); + + QString text = QString("%1 (%2 x %3)").arg(pattern->name()).arg(pattern->width()).arg(pattern->height()); + + m_lbName->setText(text); + } +} + +#include "kis_pattern_chooser.moc" + diff --git a/krita/ui/kis_pattern_chooser.h b/krita/ui/kis_pattern_chooser.h new file mode 100644 index 00000000..76514f71 --- /dev/null +++ b/krita/ui/kis_pattern_chooser.h @@ -0,0 +1,41 @@ +/* + * 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 QLabel; + +class KisPatternChooser : public KisItemChooser { + typedef KisItemChooser super; + Q_OBJECT + +public: + KisPatternChooser(QWidget *parent = 0, const char *name = 0); + virtual ~KisPatternChooser(); + +protected: + virtual void update(KoIconItem *item); + +private: + QLabel *m_lbName; +}; + +#endif // KIS_PATTERN_CHOOSER_H_ + diff --git a/krita/ui/kis_perspective_grid_manager.cpp b/krita/ui/kis_perspective_grid_manager.cpp new file mode 100644 index 00000000..13c5cb13 --- /dev/null +++ b/krita/ui/kis_perspective_grid_manager.cpp @@ -0,0 +1,159 @@ +/* + * This file is part of Krita + * + * 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 * parent) + : QObject() + , m_toggleEdition(false) + , m_view(parent) +{ + +} + + +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, 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, 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(QRect wr, QPainter *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 QPainterGridDrawer(p); + } + } + + Q_ASSERT(gridDrawer != 0); + + for( QValueList::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/krita/ui/kis_perspective_grid_manager.h b/krita/ui/kis_perspective_grid_manager.h new file mode 100644 index 00000000..a23abef3 --- /dev/null +++ b/krita/ui/kis_perspective_grid_manager.h @@ -0,0 +1,54 @@ +/* + * This file is part of Krita + * + * 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 QObject +{ + Q_OBJECT + public: + KisPerspectiveGridManager(KisView * parent); + ~KisPerspectiveGridManager(); + void setup(KActionCollection * collection); + void drawGrid(QRect wr, QPainter *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/krita/ui/kis_populate_visitor.h b/krita/ui/kis_populate_visitor.h new file mode 100644 index 00000000..ee43e825 --- /dev/null +++ b/krita/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* parent) + : m_widget(parent->listView()) + , m_parent(parent) + { } + + 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/krita/ui/kis_previewdialog.cc b/krita/ui/kis_previewdialog.cc new file mode 100644 index 00000000..6b746776 --- /dev/null +++ b/krita/ui/kis_previewdialog.cc @@ -0,0 +1,46 @@ +/* + * kis_previewdialog.cc - part of Krita + * + * 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( QWidget * parent, const char * name, bool modal, const QString &caption) + : super (parent, name, modal, caption, Ok | Cancel, Ok) +{ + QHBox* layout = new QHBox(this); + layout->setSpacing( 6 ); + + m_containerFrame = new QFrame( layout, "container" ); + + m_preview = new KisPreviewWidget( layout, "previewWidget" ); + + setMainWidget(layout); +} + +KisPreviewDialog::~KisPreviewDialog() +{ + +} + +#include "kis_previewdialog.moc" diff --git a/krita/ui/kis_previewdialog.h b/krita/ui/kis_previewdialog.h new file mode 100644 index 00000000..ef46b066 --- /dev/null +++ b/krita/ui/kis_previewdialog.h @@ -0,0 +1,44 @@ +/* + * kis_previewdialog.h -- part of Krita + * + * 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 QFrame; + +class KisPreviewDialog: public KDialogBase { + typedef KDialogBase super; + Q_OBJECT + +public: + KisPreviewDialog( QWidget* parent = 0, const char* name = 0, bool modal = false, const QString &caption=QString::null); + ~KisPreviewDialog(); + + KisPreviewWidget* previewWidget() { return m_preview; } + QFrame* container() { return m_containerFrame; } +private: + KisPreviewWidget* m_preview; + QFrame* m_containerFrame; +}; + +#endif diff --git a/krita/ui/kis_previewwidget.cc b/krita/ui/kis_previewwidget.cc new file mode 100644 index 00000000..363302f7 --- /dev/null +++ b/krita/ui/kis_previewwidget.cc @@ -0,0 +1,409 @@ +/* + * kis_previewwidget.cc - part of Krita + * + * 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( QWidget* parent, const char* name ) + : PreviewWidgetBase( parent, 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 QTimer(this)) + , m_filterTimer(new QTimer(this)) + , m_firstFilter(true) + , m_firstZoom(true) +{ + btnZoomIn->setIconSet(KGlobal::instance()->iconLoader()->loadIconSet( "viewmag+", KIcon::MainToolbar, 16 )); + connect(btnZoomIn, SIGNAL(clicked()), this, SLOT(zoomIn())); + btnZoomOut->setIconSet(KGlobal::instance()->iconLoader()->loadIconSet( "viewmag-", KIcon::MainToolbar, 16 )); + connect(btnZoomOut, SIGNAL(clicked()), this, SLOT(zoomOut())); + btnUpdate->setIconSet(KGlobal::instance()->iconLoader()->loadIconSet( "reload", KIcon::MainToolbar, 16 )); + connect(btnUpdate, SIGNAL(clicked()), this, SLOT(forceUpdate())); + + connect(radioBtnPreview, SIGNAL(toggled(bool)), this, SLOT(setPreviewDisplayed(bool))); + + connect(checkBoxAutoUpdate, SIGNAL(toggled(bool)), this, SLOT(slotSetAutoUpdate(bool))); + btnZoomOneToOne->setIconSet(KGlobal::instance()->iconLoader()->loadIconSet( "viewmag1", KIcon::MainToolbar, 16 )); + connect(btnZoomOneToOne, SIGNAL(clicked()), this, SLOT(zoomOneToOne())); + + m_progress = new KisLabelProgress(frmProgress); + m_progress->setMaximumHeight(fontMetrics().height() ); + QVBoxLayout *vbox = new QVBoxLayout( frmProgress ); + vbox->addWidget(m_progress); + m_progress->hide(); + + connect(m_zoomTimer, SIGNAL(timeout()), this, SLOT(updateZoom())); + connect(m_filterTimer, SIGNAL(timeout()), this, SLOT(runFilterHelper())); + +/* kToolBar1->insertLineSeparator(); + kToolBar1->insertButton("reload",2, true, i18n("Update")); + connect(kToolBar1->getButton(2),SIGNAL(clicked()),this,SLOT(forceUpdate())); + + kToolBar1->insertButton("",3, true, i18n("Auto Update")); + connect(kToolBar1->getButton(3),SIGNAL(clicked()),this,SLOT(toggleAutoUpdate())); + + kToolBar1->insertButton("",4, true, i18n("Switch")); + connect(kToolBar1->getButton(4),SIGNAL(clicked()),this,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; + QString monitorProfileName = cfg.monitorProfile(); + m_profile = KisMetaRegistry::instance()->csRegistry()->getProfileByName(monitorProfileName); + + QRect 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() +{ + QApplication::setOverrideCursor(KisCursor::waitCursor()); + + if(m_previewIsDisplayed) + { + if(m_dirtyPreview) + { + QSize 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->convertToQImage(m_profile, 0, 0, w, h); + m_scaledPreview = m_scaledPreview.scale(sw,sh, QImage::ScaleMax); // Use scale instead of smoothScale for speed up + } + m_preview->setImage(m_scaledPreview); + } else + { + if(m_dirtyOriginal) + { + QSize 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->convertToQImage(m_profile, 0, 0, w, h); + m_scaledOriginal = m_scaledOriginal.scale(sw,sh, QImage::ScaleMax); // Use scale instead of smoothScale for speed up + } + m_preview->setImage(m_scaledOriginal); + } + + QApplication::restoreOverrideCursor(); +} + +void KisPreviewWidget::slotSetAutoUpdate(bool set) { + m_autoupdate = set; +} + +void KisPreviewWidget::wheelEvent(QWheelEvent * 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) { + QRect 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->parentLayer()) return; + QString layerName = m_origDevice->parentLayer()->name(); + KisPaintLayerSP pl = ::qt_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->parentLayer()); + } + + // 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/krita/ui/kis_previewwidget.h b/krita/ui/kis_previewwidget.h new file mode 100644 index 00000000..f3b38e98 --- /dev/null +++ b/krita/ui/kis_previewwidget.h @@ -0,0 +1,140 @@ +/* + * kis_previewwidget.h - part of Krita + * + * 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 QWidget; +class KisProfile; +class KisFilter; +class KisFilterConfiguration; +class QTimer; +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 + +public: + /** Constructs the widget */ + KisPreviewWidget( QWidget* parent = 0, const char* name = 0 ); + virtual ~KisPreviewWidget(); + + /** returns if the preview is automatically updated */ + bool getAutoUpdate() const; + + void wheelEvent(QWheelEvent * 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 + + QImage m_scaledOriginal; /// QImage copy of the original image + bool m_dirtyOriginal; /// flag indicating that the original image is dirty + KisPaintDeviceSP m_origDevice; /// Pointer to the original image + + QImage m_scaledPreview; /// QImage 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 QImage + + KisLabelProgress *m_progress; /// Progress bar of the preview. + + QTimer * m_zoomTimer; /// Timer used to update the view whenever the zoom changes + QTimer * 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/krita/ui/kis_previewwidgetbase.ui b/krita/ui/kis_previewwidgetbase.ui new file mode 100644 index 00000000..f50fba6a --- /dev/null +++ b/krita/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 + + + + + + + + layout4 + + + + unnamed + + + + buttonGroup1 + + + GroupBoxPanel + + + + + + + unnamed + + + + radioBtnPreview + + + Pr&eview + + + true + + + Preview modified layer + + + + + radioBtnOriginal + + + Ori&ginal + + + Show original layer + + + + + + + layout5 + + + + unnamed + + + + layout4 + + + + 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/krita/ui/kis_qpaintdevice_canvas.cc b/krita/ui/kis_qpaintdevice_canvas.cc new file mode 100644 index 00000000..675b7138 --- /dev/null +++ b/krita/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 + +KisQPaintDeviceCanvasWidget::KisQPaintDeviceCanvasWidget(QWidget *parent, const char *name) + : QWidget(parent, name) +{ +} + +KisQPaintDeviceCanvasWidget::~KisQPaintDeviceCanvasWidget() +{ +} + +void KisQPaintDeviceCanvasWidget::paintEvent(QPaintEvent *e) +{ + widgetGotPaintEvent(e); +} + +void KisQPaintDeviceCanvasWidget::mousePressEvent(QMouseEvent *e) +{ + widgetGotMousePressEvent(e); +} + +void KisQPaintDeviceCanvasWidget::mouseReleaseEvent(QMouseEvent *e) +{ + widgetGotMouseReleaseEvent(e); +} + +void KisQPaintDeviceCanvasWidget::mouseDoubleClickEvent(QMouseEvent *e) +{ + widgetGotMouseDoubleClickEvent(e); +} + +void KisQPaintDeviceCanvasWidget::mouseMoveEvent(QMouseEvent *e) +{ + widgetGotMouseMoveEvent(e); +} + +void KisQPaintDeviceCanvasWidget::tabletEvent(QTabletEvent *e) +{ + widgetGotTabletEvent(e); +} + +void KisQPaintDeviceCanvasWidget::enterEvent(QEvent *e) +{ + widgetGotEnterEvent(e); +} + +void KisQPaintDeviceCanvasWidget::leaveEvent(QEvent *e) +{ + widgetGotLeaveEvent(e); +} + +void KisQPaintDeviceCanvasWidget::wheelEvent(QWheelEvent *e) +{ + widgetGotWheelEvent(e); +} + +void KisQPaintDeviceCanvasWidget::keyPressEvent(QKeyEvent *e) +{ + widgetGotKeyPressEvent(e); +} + +void KisQPaintDeviceCanvasWidget::keyReleaseEvent(QKeyEvent *e) +{ + widgetGotKeyReleaseEvent(e); +} + +void KisQPaintDeviceCanvasWidget::dragEnterEvent(QDragEnterEvent *e) +{ + widgetGotDragEnterEvent(e); +} + +void KisQPaintDeviceCanvasWidget::dropEvent(QDropEvent *e) +{ + widgetGotDropEvent(e); +} + +#ifdef Q_WS_X11 + +bool KisQPaintDeviceCanvasWidget::x11Event(XEvent *event) +{ + return KisCanvasWidget::x11Event(event, x11Display(), winId(), mapToGlobal(QPoint(0, 0))); +} + +#endif // Q_WS_X11 + +KisCanvasWidgetPainter *KisQPaintDeviceCanvasWidget::createPainter() +{ + return new KisQPaintDeviceCanvasPainter(this); +} + +#if defined(EXTENDED_X11_TABLET_SUPPORT) +void KisQPaintDeviceCanvasWidget::selectTabletDeviceEvents() +{ + KisCanvasWidget::selectTabletDeviceEvents(this); +} +#endif + diff --git a/krita/ui/kis_qpaintdevice_canvas.h b/krita/ui/kis_qpaintdevice_canvas.h new file mode 100644 index 00000000..1046337a --- /dev/null +++ b/krita/ui/kis_qpaintdevice_canvas.h @@ -0,0 +1,67 @@ +/* + * 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_QPAINTDEVICE_CANVAS_H_ +#define KIS_QPAINTDEVICE_CANVAS_H_ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "kis_global.h" +#include "kis_canvas.h" + +#ifdef Q_WS_X11 +#include +#endif // Q_WS_X11 + +class KisQPaintDeviceCanvasWidget : public virtual QWidget, public virtual KisCanvasWidget { +public: + KisQPaintDeviceCanvasWidget(QWidget *parent = 0, const char *name = 0); + ~KisQPaintDeviceCanvasWidget(); + + virtual KisCanvasWidgetPainter *createPainter(); + +#if defined(EXTENDED_X11_TABLET_SUPPORT) + virtual void selectTabletDeviceEvents(); +#endif + +protected: + virtual void paintEvent(QPaintEvent *event); + virtual void mousePressEvent(QMouseEvent *event); + virtual void mouseReleaseEvent(QMouseEvent *event); + virtual void mouseDoubleClickEvent(QMouseEvent *event); + virtual void mouseMoveEvent(QMouseEvent *event); + virtual void tabletEvent(QTabletEvent *event); + virtual void enterEvent(QEvent *event ); + virtual void leaveEvent(QEvent *event); + virtual void wheelEvent(QWheelEvent *event); + virtual void keyPressEvent(QKeyEvent *event); + virtual void keyReleaseEvent(QKeyEvent *event); + virtual void dragEnterEvent(QDragEnterEvent *event); + virtual void dropEvent(QDropEvent *event); +#ifdef Q_WS_X11 + bool x11Event(XEvent *event); +#endif // Q_WS_X11 +}; + +#endif // KIS_QPAINTDEVICE_CANVAS_H_ + diff --git a/krita/ui/kis_qpaintdevice_canvas_painter.cc b/krita/ui/kis_qpaintdevice_canvas_painter.cc new file mode 100644 index 00000000..eb68117d --- /dev/null +++ b/krita/ui/kis_qpaintdevice_canvas_painter.cc @@ -0,0 +1,647 @@ +/* + * 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" + +KisQPaintDeviceCanvasPainter::KisQPaintDeviceCanvasPainter() +{ +} + +KisQPaintDeviceCanvasPainter::KisQPaintDeviceCanvasPainter(const QPaintDevice *paintDevice) + : m_painter(paintDevice) +{ +} + +KisQPaintDeviceCanvasPainter::~KisQPaintDeviceCanvasPainter() +{ +} + +bool KisQPaintDeviceCanvasPainter::begin(KisCanvasWidget *canvasWidget, bool unclipped) +{ + QWidget *widget = dynamic_cast(canvasWidget); + + if (widget != 0) { + return m_painter.begin(widget, unclipped); + } else { + return false; + } +} + +bool KisQPaintDeviceCanvasPainter::begin(const QPaintDevice* paintDevice, bool unclipped) +{ + return m_painter.begin(paintDevice, unclipped); +} + +bool KisQPaintDeviceCanvasPainter::end() +{ + return m_painter.end(); +} + +void KisQPaintDeviceCanvasPainter::save() +{ + m_painter.save(); +} + +void KisQPaintDeviceCanvasPainter::restore() +{ + m_painter.restore(); +} + +QFontMetrics KisQPaintDeviceCanvasPainter::fontMetrics() const +{ + return m_painter.fontMetrics(); +} + +QFontInfo KisQPaintDeviceCanvasPainter::fontInfo() const +{ + return m_painter.fontInfo(); +} + +const QFont& KisQPaintDeviceCanvasPainter::font() const +{ + return m_painter.font(); +} + +void KisQPaintDeviceCanvasPainter::setFont(const QFont& font) +{ + m_painter.setFont(font); +} + +const QPen& KisQPaintDeviceCanvasPainter::pen() const +{ + return m_painter.pen(); +} + +void KisQPaintDeviceCanvasPainter::setPen(const QPen& pen) +{ + m_painter.setPen(pen); +} + +void KisQPaintDeviceCanvasPainter::setPen(Qt::PenStyle penStyle) +{ + m_painter.setPen(penStyle); +} + +void KisQPaintDeviceCanvasPainter::setPen(const QColor& color) +{ + m_painter.setPen(color);; +} + +const QBrush& KisQPaintDeviceCanvasPainter::brush() const +{ + return m_painter.brush(); +} + +void KisQPaintDeviceCanvasPainter::setBrush(const QBrush& brush) +{ + m_painter.setBrush(brush); +} + +void KisQPaintDeviceCanvasPainter::setBrush(Qt::BrushStyle brushStyle) +{ + m_painter.setBrush(brushStyle); +} + +void KisQPaintDeviceCanvasPainter::setBrush(const QColor& color) +{ + m_painter.setBrush(color); +} + +QPoint KisQPaintDeviceCanvasPainter::pos() const +{ + return m_painter.pos(); +} + +const QColor& KisQPaintDeviceCanvasPainter::backgroundColor() const +{ + return m_painter.backgroundColor(); +} + +void KisQPaintDeviceCanvasPainter::setBackgroundColor(const QColor& color) +{ + m_painter.setBackgroundColor(color); +} + +Qt::Qt::BGMode KisQPaintDeviceCanvasPainter::backgroundMode() const +{ + return m_painter.backgroundMode(); +} + +void KisQPaintDeviceCanvasPainter::setBackgroundMode(Qt::BGMode bgMode) +{ + m_painter.setBackgroundMode(bgMode); +} + +Qt::RasterOp KisQPaintDeviceCanvasPainter::rasterOp() const +{ + return m_painter.rasterOp(); +} + +void KisQPaintDeviceCanvasPainter::setRasterOp(Qt::RasterOp rasterOp) +{ + m_painter.setRasterOp(rasterOp); +} + +const QPoint& KisQPaintDeviceCanvasPainter::brushOrigin() const +{ + return m_painter.brushOrigin(); +} + +void KisQPaintDeviceCanvasPainter::setBrushOrigin(int x, int y) +{ + m_painter.setBrushOrigin(x, y); +} + +void KisQPaintDeviceCanvasPainter::setBrushOrigin(const QPoint& origin) +{ + m_painter.setBrushOrigin(origin); +} + +bool KisQPaintDeviceCanvasPainter::hasViewXForm() const +{ + return m_painter.hasViewXForm(); +} + +bool KisQPaintDeviceCanvasPainter::hasWorldXForm() const +{ + return m_painter.hasWorldXForm(); +} + +void KisQPaintDeviceCanvasPainter::setViewXForm(bool enable) +{ + m_painter.setViewXForm(enable); +} + +QRect KisQPaintDeviceCanvasPainter::window() const +{ + return m_painter.window(); +} + +void KisQPaintDeviceCanvasPainter::setWindow(const QRect& r) +{ + m_painter.setWindow(r); +} + +void KisQPaintDeviceCanvasPainter::setWindow(int x, int y, int w, int h) +{ + m_painter.setWindow(x, y, w, h); +} + +QRect KisQPaintDeviceCanvasPainter::viewport() const +{ + return m_painter.viewport(); +} + +void KisQPaintDeviceCanvasPainter::setViewport(const QRect& r) +{ + m_painter.setViewport(r); +} + +void KisQPaintDeviceCanvasPainter::setViewport(int x, int y, int w, int h) +{ + m_painter.setViewport(x, y, w, h); +} + +void KisQPaintDeviceCanvasPainter::setWorldXForm(bool enable) +{ + m_painter.setWorldXForm(enable); +} + +const QWMatrix& KisQPaintDeviceCanvasPainter::worldMatrix() const +{ + return m_painter.worldMatrix(); +} + +void KisQPaintDeviceCanvasPainter::setWorldMatrix(const QWMatrix& matrix, bool combine) +{ + m_painter.setWorldMatrix(matrix, combine); +} + +void KisQPaintDeviceCanvasPainter::saveWorldMatrix() +{ + m_painter.saveWorldMatrix(); +} + +void KisQPaintDeviceCanvasPainter::restoreWorldMatrix() +{ + m_painter.restoreWorldMatrix(); +} + +void KisQPaintDeviceCanvasPainter::scale(double sx, double sy) +{ + m_painter.scale(sx, sy); +} + +void KisQPaintDeviceCanvasPainter::shear(double sh, double sv) +{ + m_painter.shear(sh, sv); +} + +void KisQPaintDeviceCanvasPainter::rotate(double a) +{ + m_painter.rotate(a); +} + +void KisQPaintDeviceCanvasPainter::translate(double dx, double dy) +{ + m_painter.translate(dx, dy); +} + +void KisQPaintDeviceCanvasPainter::resetXForm() +{ + m_painter.resetXForm(); +} + +double KisQPaintDeviceCanvasPainter::translationX() const +{ + return m_painter.translationX(); +} + +double KisQPaintDeviceCanvasPainter::translationY() const +{ + return m_painter.translationY(); +} + +QPoint KisQPaintDeviceCanvasPainter::xForm(const QPoint& point) const +{ + return m_painter.xForm(point); +} + +QRect KisQPaintDeviceCanvasPainter::xForm(const QRect& r) const +{ + return m_painter.xForm(r); +} + +QPointArray KisQPaintDeviceCanvasPainter::xForm(const QPointArray& pointArray) const +{ + return m_painter.xForm(pointArray); +} + +QPointArray KisQPaintDeviceCanvasPainter::xForm(const QPointArray& pointArray, int index, int npoints) const +{ + return m_painter.xForm(pointArray, index, npoints); +} + +QPoint KisQPaintDeviceCanvasPainter::xFormDev(const QPoint& point) const +{ + return m_painter.xFormDev(point); +} + +QRect KisQPaintDeviceCanvasPainter::xFormDev(const QRect& r) const +{ + return m_painter.xFormDev(r); +} + +QPointArray KisQPaintDeviceCanvasPainter::xFormDev(const QPointArray& pointArray) const +{ + return m_painter.xFormDev(pointArray); +} + +QPointArray KisQPaintDeviceCanvasPainter::xFormDev(const QPointArray& pointArray, int index, int npoints) const +{ + return m_painter.xFormDev(pointArray, index, npoints); +} + +void KisQPaintDeviceCanvasPainter::setClipping(bool enable) +{ + m_painter.setClipping(enable); +} + +bool KisQPaintDeviceCanvasPainter::hasClipping() const +{ + return m_painter.hasClipping(); +} + +QRegion KisQPaintDeviceCanvasPainter::clipRegion(QPainter::CoordinateMode mode) const +{ + return m_painter.clipRegion(mode); +} + +void KisQPaintDeviceCanvasPainter::setClipRect(const QRect& r, QPainter::CoordinateMode mode) +{ + m_painter.setClipRect(r, mode); +} + +void KisQPaintDeviceCanvasPainter::setClipRect(int x, int y, int w, int h, QPainter::CoordinateMode mode) +{ + m_painter.setClipRect(x, y, w, h, mode); +} + +void KisQPaintDeviceCanvasPainter::setClipRegion(const QRegion& rgn, QPainter::CoordinateMode mode) +{ + m_painter.setClipRegion(rgn, mode); +} + +void KisQPaintDeviceCanvasPainter::drawPoint(int x, int y) +{ + m_painter.drawPoint(x, y); +} + +void KisQPaintDeviceCanvasPainter::drawPoint(const QPoint& point) +{ + m_painter.drawPoint(point); +} + +void KisQPaintDeviceCanvasPainter::drawPoints(const QPointArray& pointArray, int index, int npoints) +{ + m_painter.drawPoints(pointArray, index, npoints); +} + +void KisQPaintDeviceCanvasPainter::moveTo(int x, int y) +{ + m_painter.moveTo(x, y); +} + +void KisQPaintDeviceCanvasPainter::moveTo(const QPoint& point) +{ + m_painter.moveTo(point); +} + +void KisQPaintDeviceCanvasPainter::lineTo(int x, int y) +{ + m_painter.lineTo(x, y); +} + +void KisQPaintDeviceCanvasPainter::lineTo(const QPoint& point) +{ + m_painter.lineTo(point); +} + +void KisQPaintDeviceCanvasPainter::drawLine(int x1, int y1, int x2, int y2) +{ + m_painter.drawLine(x1, y1, x2, y2); +} + +void KisQPaintDeviceCanvasPainter::drawLine(const QPoint& start, const QPoint& end) +{ + m_painter.drawLine(start, end); +} + +void KisQPaintDeviceCanvasPainter::drawRect(int x, int y, int w, int h) +{ + m_painter.drawRect(x, y, w, h); +} + +void KisQPaintDeviceCanvasPainter::drawRect(const QRect& r) +{ + m_painter.drawRect(r); +} + +void KisQPaintDeviceCanvasPainter::drawWinFocusRect(int x, int y, int w, int h) +{ + m_painter.drawWinFocusRect(x, y, w, h); +} + +void KisQPaintDeviceCanvasPainter::drawWinFocusRect(int x, int y, int w, int h, const QColor& bgColor) +{ + m_painter.drawWinFocusRect(x, y, w, h, bgColor); +} + +void KisQPaintDeviceCanvasPainter::drawWinFocusRect(const QRect& r) +{ + m_painter.drawWinFocusRect(r); +} + +void KisQPaintDeviceCanvasPainter::drawWinFocusRect(const QRect& r, const QColor& bgColor) +{ + m_painter.drawWinFocusRect(r, bgColor); +} + +void KisQPaintDeviceCanvasPainter::drawRoundRect(int x, int y, int w, int h, int xRnd, int yRnd) +{ + m_painter.drawRoundRect(x, y, w, h, xRnd, yRnd); +} + +void KisQPaintDeviceCanvasPainter::drawRoundRect(const QRect& r, int xRnd, int yRnd) +{ + m_painter.drawRoundRect(r, xRnd, yRnd); +} + +void KisQPaintDeviceCanvasPainter::drawEllipse(int x, int y, int w, int h) +{ + m_painter.drawEllipse(x, y, w, h); +} + +void KisQPaintDeviceCanvasPainter::drawEllipse(const QRect& r) +{ + m_painter.drawEllipse(r); +} + +void KisQPaintDeviceCanvasPainter::drawArc(int x, int y, int w, int h, int a, int alen) +{ + m_painter.drawArc(x, y, w, h, a, alen); +} + +void KisQPaintDeviceCanvasPainter::drawArc(const QRect& r, int a, int alen) +{ + m_painter.drawArc(r, a, alen); +} + +void KisQPaintDeviceCanvasPainter::drawPie(int x, int y, int w, int h, int a, int alen) +{ + m_painter.drawPie(x, y, w, h, a, alen); +} + +void KisQPaintDeviceCanvasPainter::drawPie(const QRect& r, int a, int alen) +{ + m_painter.drawPie(r, a, alen); +} + +void KisQPaintDeviceCanvasPainter::drawChord(int x, int y, int w, int h, int a, int alen) +{ + m_painter.drawChord(x, y, w, h, a, alen); +} + +void KisQPaintDeviceCanvasPainter::drawChord(const QRect& r, int a, int alen) +{ + m_painter.drawChord(r, a, alen); +} + +void KisQPaintDeviceCanvasPainter::drawLineSegments(const QPointArray& pointArray, int index, int nlines) +{ + m_painter.drawLineSegments(pointArray, index, nlines); +} + +void KisQPaintDeviceCanvasPainter::drawPolyline(const QPointArray& pointArray, int index, int npoints) +{ + m_painter.drawPolyline(pointArray, index, npoints); +} + +void KisQPaintDeviceCanvasPainter::drawPolygon(const QPointArray& pointArray, bool winding, int index, int npoints) +{ + m_painter.drawPolygon(pointArray, winding, index, npoints); +} + +void KisQPaintDeviceCanvasPainter::drawConvexPolygon(const QPointArray& pointArray, int index, int npoints) +{ + m_painter.drawConvexPolygon(pointArray, index, npoints); +} + +void KisQPaintDeviceCanvasPainter::drawCubicBezier(const QPointArray& pointArray, int index) +{ + m_painter.drawCubicBezier(pointArray, index); +} + +void KisQPaintDeviceCanvasPainter::drawPixmap(int x, int y, const QPixmap& pixmap, int sx, int sy, int sw, int sh) +{ + m_painter.drawPixmap(x, y, pixmap, sx, sy, sw, sh); +} + +void KisQPaintDeviceCanvasPainter::drawPixmap(const QPoint& point, const QPixmap& pixmap, const QRect& sr) +{ + m_painter.drawPixmap(point, pixmap, sr); +} + +void KisQPaintDeviceCanvasPainter::drawPixmap(const QPoint& point, const QPixmap& pixmap) +{ + m_painter.drawPixmap(point, pixmap); +} + +void KisQPaintDeviceCanvasPainter::drawPixmap(const QRect& r, const QPixmap& pixmap) +{ + m_painter.drawPixmap(r, pixmap); +} + +void KisQPaintDeviceCanvasPainter::drawImage(int x, int y, const QImage& image, int sx, int sy, int sw, int sh, int conversionFlags) +{ + m_painter.drawImage(x, y, image, sx, sy, sw, sh, conversionFlags); +} + +void KisQPaintDeviceCanvasPainter::drawImage(const QPoint& point, const QImage& image, const QRect& sr, int conversionFlags) +{ + m_painter.drawImage(point, image, sr, conversionFlags); +} + +void KisQPaintDeviceCanvasPainter::drawImage(const QPoint& point, const QImage& image, int conversion_flags) +{ + m_painter.drawImage(point, image, conversion_flags); +} + +void KisQPaintDeviceCanvasPainter::drawImage(const QRect& r, const QImage& image) +{ + m_painter.drawImage(r, image); +} + +void KisQPaintDeviceCanvasPainter::drawTiledPixmap(int x, int y, int w, int h, const QPixmap& pixmap, int sx, int sy) +{ + m_painter.drawTiledPixmap(x, y, w, h, pixmap, sx, sy); +} + +void KisQPaintDeviceCanvasPainter::drawTiledPixmap(const QRect& r, const QPixmap& pixmap, const QPoint& point) +{ + m_painter.drawTiledPixmap(r, pixmap, point); +} + +void KisQPaintDeviceCanvasPainter::drawTiledPixmap(const QRect& r, const QPixmap& pixmap) +{ + m_painter.drawTiledPixmap(r, pixmap); +} + +void KisQPaintDeviceCanvasPainter::fillRect(int x, int y, int w, int h, const QBrush& brush) +{ + m_painter.fillRect(x, y, w, h, brush); +} + +void KisQPaintDeviceCanvasPainter::fillRect(const QRect& r, const QBrush& brush) +{ + m_painter.fillRect(r, brush); +} + +void KisQPaintDeviceCanvasPainter::eraseRect(int x, int y, int w, int h) +{ + m_painter.eraseRect(x, y, w, h); +} + +void KisQPaintDeviceCanvasPainter::eraseRect(const QRect& r) +{ + m_painter.eraseRect(r); +} + +void KisQPaintDeviceCanvasPainter::drawText(int x, int y, const QString& text, int len, QPainter::TextDirection dir) +{ + m_painter.drawText(x, y, text, len, dir); +} + +void KisQPaintDeviceCanvasPainter::drawText(const QPoint& point, const QString& text, int len, QPainter::TextDirection dir) +{ + m_painter.drawText(point, text, len, dir); +} + +void KisQPaintDeviceCanvasPainter::drawText(int x, int y, const QString& text, int pos, int len, QPainter::TextDirection dir) +{ + m_painter.drawText(x, y, text, pos, len, dir); +} + +void KisQPaintDeviceCanvasPainter::drawText(const QPoint& point, const QString& text, int pos, int len, QPainter::TextDirection dir) +{ + m_painter.drawText(point, text, pos, len, dir); +} + +void KisQPaintDeviceCanvasPainter::drawText(int x, int y, int w, int h, int flags, const QString& text, int len, QRect *br, QTextParag **intern) +{ + m_painter.drawText(x, y, w, h, flags, text, len, br, intern); +} + +void KisQPaintDeviceCanvasPainter::drawText(const QRect& r, int flags, const QString& text, int len, QRect *br, QTextParag **intern) +{ + m_painter.drawText(r, flags, text, len, br, intern); +} + +void KisQPaintDeviceCanvasPainter::drawTextItem(int x, int y, const QTextItem& ti, int textflags) +{ + m_painter.drawTextItem(x, y, ti, textflags); +} + +void KisQPaintDeviceCanvasPainter::drawTextItem(const QPoint& p, const QTextItem& ti, int textflags) +{ + m_painter.drawTextItem(p, ti, textflags); +} + +QRect KisQPaintDeviceCanvasPainter::boundingRect(int x, int y, int w, int h, int flags, const QString& text, int len, QTextParag **intern) +{ + return m_painter.boundingRect(x, y, w, h, flags, text, len, intern); +} + +QRect KisQPaintDeviceCanvasPainter::boundingRect(const QRect& r, int flags, const QString& text, int len, QTextParag **intern) +{ + return m_painter.boundingRect(r, flags, text, len, intern); +} + +int KisQPaintDeviceCanvasPainter::tabStops() const +{ + return m_painter.tabStops(); +} + +void KisQPaintDeviceCanvasPainter::setTabStops(int ts) +{ + m_painter.setTabStops(ts); +} + +int *KisQPaintDeviceCanvasPainter::tabArray() const +{ + return m_painter.tabArray(); +} + +void KisQPaintDeviceCanvasPainter::setTabArray(int *ts) +{ + m_painter.setTabArray(ts); +} + + diff --git a/krita/ui/kis_qpaintdevice_canvas_painter.h b/krita/ui/kis_qpaintdevice_canvas_painter.h new file mode 100644 index 00000000..ddc306f1 --- /dev/null +++ b/krita/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_QPAINTDEVICE_CANVAS_PAINTER_H_ +#define KIS_QPAINTDEVICE_CANVAS_PAINTER_H_ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "kis_global.h" +#include "kis_canvas_painter.h" + +class KisQPaintDeviceCanvasPainter : public KisCanvasWidgetPainter { +public: + KisQPaintDeviceCanvasPainter(); + KisQPaintDeviceCanvasPainter(const QPaintDevice *paintDevice); + virtual ~KisQPaintDeviceCanvasPainter(); + + bool begin(const QPaintDevice* paintDevice, bool unclipped = false); + + virtual bool begin(KisCanvasWidget *canvasWidget, bool unclipped = false); + virtual bool end(); + + virtual void save(); + virtual void restore(); + + virtual QFontMetrics fontMetrics() const; + virtual QFontInfo fontInfo() const; + + virtual const QFont& font() const; + virtual void setFont(const QFont&); + virtual const QPen& pen() const; + virtual void setPen(const QPen&); + virtual void setPen(Qt::PenStyle); + virtual void setPen(const QColor&); + virtual const QBrush&brush() const; + virtual void setBrush(const QBrush&); + virtual void setBrush(Qt::BrushStyle); + virtual void setBrush(const QColor&); + virtual QPoint pos() const; + + virtual const QColor&backgroundColor() const; + virtual void setBackgroundColor(const QColor&); + virtual Qt::BGMode backgroundMode() const; + virtual void setBackgroundMode(Qt::BGMode); + virtual Qt::RasterOp rasterOp() const; + virtual void setRasterOp(Qt::RasterOp); + virtual const QPoint&brushOrigin() const; + virtual void setBrushOrigin(int x, int y); + virtual void setBrushOrigin(const QPoint&); + + virtual bool hasViewXForm() const; + virtual bool hasWorldXForm() const; + + virtual void setViewXForm(bool); + virtual QRect window() const; + virtual void setWindow(const QRect&); + virtual void setWindow(int x, int y, int w, int h); + virtual QRect viewport() const; + virtual void setViewport(const QRect&); + virtual void setViewport(int x, int y, int w, int h); + + virtual void setWorldXForm(bool); + virtual const QWMatrix&worldMatrix() const; + virtual void setWorldMatrix(const QWMatrix&, 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 QPoint xForm(const QPoint&) const; + virtual QRect xForm(const QRect&) const; + virtual QPointArray xForm(const QPointArray&) const; + virtual QPointArray xForm(const QPointArray&, int index, int npoints) const; + virtual QPoint xFormDev(const QPoint&) const; + virtual QRect xFormDev(const QRect&) const; + virtual QPointArray xFormDev(const QPointArray&) const; + virtual QPointArray xFormDev(const QPointArray&, int index, int npoints) const; + + virtual void setClipping(bool); + virtual bool hasClipping() const; + virtual QRegion clipRegion(QPainter::CoordinateMode = QPainter::CoordDevice) const; + virtual void setClipRect(const QRect&, QPainter::CoordinateMode = QPainter::CoordDevice); + virtual void setClipRect(int x, int y, int w, int h, QPainter::CoordinateMode = QPainter::CoordDevice); + virtual void setClipRegion(const QRegion&, QPainter::CoordinateMode = QPainter::CoordDevice); + + virtual void drawPoint(int x, int y); + virtual void drawPoint(const QPoint&); + virtual void drawPoints(const QPointArray& a, int index=0, int npoints=-1); + virtual void moveTo(int x, int y); + virtual void moveTo(const QPoint&); + virtual void lineTo(int x, int y); + virtual void lineTo(const QPoint&); + virtual void drawLine(int x1, int y1, int x2, int y2); + virtual void drawLine(const QPoint&, const QPoint&); + virtual void drawRect(int x, int y, int w, int h); + virtual void drawRect(const QRect&); + virtual void drawWinFocusRect(int x, int y, int w, int h); + virtual void drawWinFocusRect(int x, int y, int w, int h, const QColor&bgColor); + virtual void drawWinFocusRect(const QRect&); + virtual void drawWinFocusRect(const QRect&, const QColor&bgColor); + virtual void drawRoundRect(int x, int y, int w, int h, int = 25, int = 25); + virtual void drawRoundRect(const QRect&, int = 25, int = 25); + virtual void drawEllipse(int x, int y, int w, int h); + virtual void drawEllipse(const QRect&); + virtual void drawArc(int x, int y, int w, int h, int a, int alen); + virtual void drawArc(const QRect&, int a, int alen); + virtual void drawPie(int x, int y, int w, int h, int a, int alen); + virtual void drawPie(const QRect&, int a, int alen); + virtual void drawChord(int x, int y, int w, int h, int a, int alen); + virtual void drawChord(const QRect&, int a, int alen); + virtual void drawLineSegments(const QPointArray&, int index=0, int nlines=-1); + virtual void drawPolyline(const QPointArray&, int index=0, int npoints=-1); + virtual void drawPolygon(const QPointArray&, bool winding=FALSE, int index=0, int npoints=-1); + virtual void drawConvexPolygon(const QPointArray&, int index=0, int npoints=-1); + virtual void drawCubicBezier(const QPointArray&, int index=0); + virtual void drawPixmap(int x, int y, const QPixmap&, int sx=0, int sy=0, int sw=-1, int sh=-1); + virtual void drawPixmap(const QPoint&, const QPixmap&, const QRect&sr); + virtual void drawPixmap(const QPoint&, const QPixmap&); + virtual void drawPixmap(const QRect&, const QPixmap&); + virtual void drawImage(int x, int y, const QImage&, int sx = 0, int sy = 0, int sw = -1, int sh = -1, int conversionFlags = 0); + virtual void drawImage(const QPoint&, const QImage&, const QRect&sr, int conversionFlags = 0); + virtual void drawImage(const QPoint&, const QImage&, int conversion_flags = 0); + virtual void drawImage(const QRect&, const QImage&); + virtual void drawTiledPixmap(int x, int y, int w, int h, const QPixmap&, int sx=0, int sy=0); + virtual void drawTiledPixmap(const QRect&, const QPixmap&, const QPoint&); + virtual void drawTiledPixmap(const QRect&, const QPixmap&); + //virtual void drawPicture(const QPicture&); + //virtual void drawPicture(int x, int y, const QPicture&); + //virtual void drawPicture(const QPoint&, const QPicture&); + + virtual void fillRect(int x, int y, int w, int h, const QBrush&); + virtual void fillRect(const QRect&, const QBrush&); + virtual void eraseRect(int x, int y, int w, int h); + virtual void eraseRect(const QRect&); + + virtual void drawText(int x, int y, const QString&, int len = -1, QPainter::TextDirection dir = QPainter::Auto); + virtual void drawText(const QPoint&, const QString&, int len = -1, QPainter::TextDirection dir = QPainter::Auto); + + virtual void drawText(int x, int y, const QString&, int pos, int len, QPainter::TextDirection dir = QPainter::Auto); + virtual void drawText(const QPoint&p, const QString&, int pos, int len, QPainter::TextDirection dir = QPainter::Auto); + + virtual void drawText(int x, int y, int w, int h, int flags, const QString&, int len = -1, QRect *br=0, QTextParag **intern=0); + virtual void drawText(const QRect&, int flags, const QString&, int len = -1, QRect *br=0, QTextParag **intern=0); + + virtual void drawTextItem(int x, int y, const QTextItem&ti, int textflags = 0); + virtual void drawTextItem(const QPoint& p, const QTextItem&ti, int textflags = 0); + + virtual QRect boundingRect(int x, int y, int w, int h, int flags, const QString&, int len = -1, QTextParag **intern=0); + virtual QRect boundingRect(const QRect&, int flags, const QString&, int len = -1, QTextParag **intern=0); + + virtual int tabStops() const; + virtual void setTabStops(int); + virtual int *tabArray() const; + virtual void setTabArray(int *); + +protected: + QPainter m_painter; +}; + +#endif // KIS_QPAINTDEVICE_CANVAS_PAINTER_H_ + diff --git a/krita/ui/kis_resource_mediator.cc b/krita/ui/kis_resource_mediator.cc new file mode 100644 index 00000000..e4040cd2 --- /dev/null +++ b/krita/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, + QObject *parent, + const char *name) : super(parent, name), m_chooser(chooser) +{ + Q_ASSERT(chooser); + m_activeItem = 0; + + connect(m_chooser, SIGNAL(selected(KoIconItem*)), SLOT(setActiveItem(KoIconItem*))); +} + +KisResourceMediator::~KisResourceMediator() +{ +} + +void KisResourceMediator::connectServer(KisResourceServerBase* rServer) +{ + // Add the initially loaded items + QValueList resources = rServer->resources(); + QValueList::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, SIGNAL(resourceAdded(KisResource*)), + this, 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.contains(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; +} + +QWidget *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/krita/ui/kis_resource_mediator.h b/krita/ui/kis_resource_mediator.h new file mode 100644 index 00000000..55623a6e --- /dev/null +++ b/krita/ui/kis_resource_mediator.h @@ -0,0 +1,72 @@ +/* + * 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 QObject { + Q_OBJECT + typedef QObject super; + +public: + KisResourceMediator(KisItemChooser *chooser, + QObject *parent = 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; + QWidget *chooserWidget() const; + +public slots: + + void setActiveItem(KoIconItem *item); + +signals: + void activatedResource(KisResource *r); + +private slots: + void rServerAddedResource(KisResource *resource); + +private: + KisItemChooser *m_chooser; + QMap m_items; + KoIconItem *m_activeItem; +}; + +#endif // KIS_RESOURCE_MEDIATOR_H_ + diff --git a/krita/ui/kis_resourceserver.cc b/krita/ui/kis_resourceserver.cc new file mode 100644 index 00000000..c72f9b80 --- /dev/null +++ b/krita/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(QString type) + : m_type(type), m_loaded(false) +{ +} + +KisResourceServerBase::~KisResourceServerBase() +{ +} + +void KisResourceServerBase::loadResources(QStringList filenames) +{ + QStringList uniqueFiles; + + while( !filenames.empty() ) + { + + QString front = *filenames.begin(); + filenames.pop_front(); + + QString fname = QFileInfo(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.find(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; +} + +QValueList KisResourceServerBase::resources() +{ + if(!m_loaded) { + return QValueList(); + } + + 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 QThread { + +public: + + ResourceLoaderThread(KisResourceServerBase * server, QStringList files) + : QThread() + , m_server(server) + , m_fileNames( files ) + { + } + + + void run() + { + m_server->loadResources(m_fileNames); + } + +private: + + KisResourceServerBase * m_server; + QStringList m_fileNames; + +}; + +QStringList getFileNames( QString extensions, QString type ) +{ + QStringList extensionList = QStringList::split(":", extensions); + QStringList fileNames; + + QStringList::Iterator it; + for ( it = extensionList.begin(); it != extensionList.end(); ++it ) { + QString 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/krita/ui/kis_resourceserver.h b/krita/ui/kis_resourceserver.h new file mode 100644 index 00000000..aa15f72e --- /dev/null +++ b/krita/ui/kis_resourceserver.h @@ -0,0 +1,90 @@ +/* + * 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 QObject { + Q_OBJECT +public: + KisResourceServerBase(QString type); + virtual ~KisResourceServerBase(); + + void loadResources(QStringList filenames); + /// Adds an already loaded resource to the server + void addResource(KisResource* resource); + QValueList resources(); + QString type() { return m_type; }; + +signals: + void resourceAdded(KisResource*); + +protected: + virtual KisResource* createResource( QString filename ) = 0; + +private: + QValueList m_resources; + QString m_type; + + bool m_loaded; + +}; + + +template class KisResourceServer : public KisResourceServerBase { + typedef KisResourceServerBase super; + +public: + KisResourceServer(QString type) :super( type ) {} + virtual ~KisResourceServer(){} + +private: + KisResource* createResource( QString 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/krita/ui/kis_ruler.cc b/krita/ui/kis_ruler.cc new file mode 100644 index 00000000..1da94b15 --- /dev/null +++ b/krita/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, QWidget *parent, const char *name) : super(parent, 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(Q_INT32 w, Q_INT32 h) +{ + QPainter 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() +{ + Q_INT32 w; + Q_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 QPixmap(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(Q_INT32 x, Q_INT32 y) +{ + if (m_pixmapBuffer) { + if (m_orientation == Qt::Horizontal) { + if (m_currentPosition != -1) + repaint(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) + repaint(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(Q_INT32 xpos, Q_INT32 ypos) +{ + if (m_orientation == Qt::Horizontal) + m_firstVisible = xpos; + else + m_firstVisible = ypos; + + drawRuler(); + update(); + updatePointer(m_currentPosition, m_currentPosition); +} + +void KisRuler::paintEvent(QPaintEvent *e) +{ + if (m_pixmapBuffer) { + const QRect& rect = e->rect(); + + bitBlt(this, rect.topLeft(), m_pixmapBuffer, rect); + super::paintEvent(e); + } +} + +void KisRuler::drawRuler() +{ + QPainter p; + QString buf; + Q_INT32 st1 = 0; + Q_INT32 st2 = 0; + Q_INT32 st3 = 0; + Q_INT32 st4 = 0; + + if (!m_pixmapBuffer) + return; + + p.begin(m_pixmapBuffer); + p.setPen(colorGroup().text()); + p.setBackgroundColor(colorGroup().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; + Q_INT32 step = qRound(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; + } + + Q_INT32 start = (Q_INT32)(KoUnit::fromUserValue(m_firstVisible, m_unit) / m_zoom); + Q_INT32 pos = 0; + + if (m_orientation == Qt::Horizontal) { + do { + pos = (Q_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(QABS(start)); + drawNums(&p, pos, 4, buf, true); + } + + start++; + } while (pos < m_pixmapBuffer->width()); + } else { + do { + pos = (Q_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(QABS(start)); + drawNums(&p, 4, pos, buf, false); + } + + start++; + } while (pos < m_pixmapBuffer->height()); + } + + p.end(); +} + +void KisRuler::resizeEvent(QResizeEvent *) +{ + recalculateSize(); +} + +void KisRuler::styleChange(QStyle& oldStyle) +{ + Q_UNUSED(oldStyle); + updateGeometry(); + drawRuler(); +} + +void KisRuler::paletteChange(const QPalette& 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(QPainter *p, Q_INT32 x, Q_INT32 y, QString& num, bool orientationHoriz) +{ + if (orientationHoriz) + x -= 7; + else + y -= 8; + + for (Q_UINT32 k = 0; k < num.length(); k++) { + Q_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/krita/ui/kis_ruler.h b/krita/ui/kis_ruler.h new file mode 100644 index 00000000..51153912 --- /dev/null +++ b/krita/ui/kis_ruler.h @@ -0,0 +1,80 @@ +/* + * 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 Krita. Also: start units with 0, +// print every 100 units. + +#define RULER_THICKNESS 20 + +class QPainter; + +class KisRuler : public QFrame { + Q_OBJECT + typedef QFrame super; + +public: + KisRuler(Qt::Orientation, QWidget *parent = 0, const char *name = 0); + virtual ~KisRuler(); + +public: + KoUnit::Unit unit() const; + +public slots: + void setZoom(double zoom); + void updatePointer(Q_INT32 x, Q_INT32 y); + void updateVisibleArea(Q_INT32 xpos, Q_INT32 ypos); + void setUnit(KoUnit::Unit u); + void hide(); + void show(); + +protected: + virtual void paintEvent(QPaintEvent *e); + virtual void resizeEvent(QResizeEvent *e); + virtual void styleChange(QStyle& oldStyle); + virtual void paletteChange(const QPalette& oldPalette); + + void recalculateSize(); + void drawRuler(); + void initMarker(Q_INT32 w, Q_INT32 h); + void drawNums(QPainter *gc, Q_INT32 x, Q_INT32 y, QString& num, bool orientationHoriz); + +private: + KoUnit::Unit m_unit; + Qt::Orientation m_orientation; + Q_INT32 m_firstVisible; + Q_INT32 m_currentPosition; + QPixmap *m_pixmapBuffer; + QPixmap m_pixmapMarker; + QPixmap m_pixmapNums; + double m_zoom; + +private: + static const char *m_nums[]; +}; + +#endif // KIS_RULER_H_ + diff --git a/krita/ui/kis_save_visitor.h b/krita/ui/kis_save_visitor.h new file mode 100644 index 00000000..ceb07eb7 --- /dev/null +++ b/krita/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, Q_UINT32 &count) : + KisLayerVisitor(), + m_count(count) + { + m_external = false; + m_img = img; + m_store = store; + } + +public: + void setExternalUri(QString &uri) + { + m_external = true; + m_uri = uri; + } + + virtual bool visit(KisPaintLayer *layer) + { + //connect(*layer->paintDevice(), SIGNAL(ioProgress(Q_INT8)), m_img, SLOT(slotIOProgress(Q_INT8))); + + QString location = m_external ? QString::null : m_uri; + location += m_img->name() + QString("/layers/layer%1").arg(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 ? QString::null : m_uri; + location += m_img->name() + QString("/layers/layer%1").arg(m_count) + ".icc"; + + if (m_store->open(location)) { + m_store->write(annotation->annotation()); + m_store->close(); + } + } + } + + if (layer->hasMask()) { + KisPaintDeviceSP mask = layer->getMask(); + + if (mask) { + // save layer profile + location = m_external ? QString::null : m_uri; + location += m_img->name() + QString("/layers/layer%1").arg(m_count) + ".mask"; + + if (m_store->open(location)) { + if (!mask->write(m_store)) { + mask->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()) { + QString location = m_external ? QString::null : m_uri; + location += m_img->name() + QString("/layers/layer%1").arg(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()) { + QString location = m_external ? QString::null : m_uri; + location = m_external ? QString::null : m_uri; + location += m_img->name() + QString("/layers/layer%1").arg(m_count) + ".filterconfig"; + + if (m_store->open(location)) { + QString s = layer->filter()->toString(); + m_store->write(s.utf8(), qstrlen(s.utf8())); + m_store->close(); + } + } + m_count++; + return true; + } + +private: + KisImageSP m_img; + KoStore *m_store; + bool m_external; + QString m_uri; + Q_UINT32 &m_count; +}; + +#endif // KIS_SAVE_VISITOR_H_ + diff --git a/krita/ui/kis_savexml_visitor.h b/krita/ui/kis_savexml_visitor.h new file mode 100644 index 00000000..f45466cd --- /dev/null +++ b/krita/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(QDomDocument doc, QDomElement element, Q_UINT32 &count, bool root=false) : + KisLayerVisitor(), + m_doc(doc), + m_count(count), + m_root(root) + { + m_elem = element; + } + +public: + virtual bool visit(KisPaintLayer *layer) + { + QDomElement 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", QString("layer%1").arg(m_count)); + layerElement.setAttribute("colorspacename", layer->paintDevice()->colorSpace()->id().id()); + layerElement.setAttribute("hasmask", layer->hasMask()); + m_elem.appendChild(layerElement); + + if(layer->paintDevice()->hasExifInfo()) + { + QDomElement exifElmt = layer->paintDevice()->exifInfo()->save(m_doc); + layerElement.appendChild(exifElmt); + } + m_count++; + return true; + } + + virtual bool visit(KisGroupLayer *layer) + { + QDomElement 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); + } + + QDomElement 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) + { + QDomElement 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", QString("layer%1").arg(m_count)); + layerElement.setAttribute("x", layer->x()); + layerElement.setAttribute("y", layer->y()); + m_elem.appendChild(layerElement); + + m_count++; + return true; + } + +private: + QDomDocument m_doc; + QDomElement m_elem; + Q_UINT32 &m_count; + bool m_root; +}; + +#endif // KIS_SAVEXML_VISITOR_H_ + diff --git a/krita/ui/kis_selection_manager.cc b/krita/ui/kis_selection_manager.cc new file mode 100644 index 00000000..d97fca0c --- /dev/null +++ b/krita/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 * parent, KisDoc * doc) + : m_parent(parent), + 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, + SLOT(cut()), + collection, + "cut"); + + m_copy = KStdAction::copy(this, + SLOT(copy()), + collection, + "copy"); + + m_paste = KStdAction::paste(this, + SLOT(paste()), + collection, + "paste"); + + m_pasteNew = new KAction(i18n("Paste into &New Image"), + 0, 0, + this, SLOT(pasteNew()), + collection, + "paste_new"); + + + m_selectAll = KStdAction::selectAll(this, + SLOT(selectAll()), + collection, + "select_all"); + + m_deselect = KStdAction::deselect(this, + SLOT(deselect()), + collection, + "deselect"); + + + m_clear = KStdAction::clear(this, + SLOT(clear()), + collection, + "clear"); + + m_reselect = new KAction(i18n("&Reselect"), + 0, "Ctrl+Shift+D", + this, SLOT(reselect()), + collection, "reselect"); + + m_invert = new KAction(i18n("&Invert"), + 0, "Ctrl+I", + this, SLOT(invert()), + collection, "invert"); + + + m_toNewLayer = new KAction(i18n("Copy Selection to New Layer"), + 0, "Ctrl+J", + this, SLOT(copySelectionToNewLayer()), + collection, "copy_selection_to_new_layer"); + + + m_cutToNewLayer = new KAction(i18n("Cut Selection to New Layer"), + 0, "Ctrl+Shift+J", + this, SLOT(cutToNewLayer()), + collection, "cut_selection_to_new_layer"); + + m_feather = new KAction(i18n("Feather"), + 0, "Ctrl+Alt+D", + this, SLOT(feather()), + collection, "feather"); + + m_fillForegroundColor = new KAction(i18n("Fill with Foreground Color"), + "Alt+backspace", this, + SLOT(fillForegroundColor()), + collection, + "fill_selection_foreground_color"); + m_fillBackgroundColor = new KAction(i18n("Fill with Background Color"), + "backspace", this, + SLOT(fillBackgroundColor()), + collection, + "fill_selection_background_color"); + m_fillPattern = new KAction(i18n("Fill with Pattern"), + 0, this, + SLOT(fillPattern()), + collection, + "fill_selection_pattern"); + + m_toggleDisplaySelection = new KToggleAction(i18n("Display Selection"), "Ctrl+h", this, 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, SLOT(border()), + collection, "border"); + m_expand = + new KAction(i18n("Expand..."), + 0, 0, + this, SLOT(expand()), + collection, "expand"); + + m_smooth = + new KAction(i18n("Smooth..."), + 0, 0, + this, SLOT(smooth()), + collection, "smooth"); + + + m_contract = + new KAction(i18n("Contract..."), + 0, 0, + this, SLOT(contract()), + collection, "contract"); + m_similar = + new KAction(i18n("Similar"), + 0, 0, + this, SLOT(similar()), + collection, "similar"); + + + m_transform + = new KAction(i18n("Transform..."), + 0, 0, + this, SLOT(transform()), + collection, "transform_selection"); + + +// m_load +// = new KAction(i18n("Load..."), +// 0, 0, +// this, SLOT(load()), +// collection, "load_selection"); +// +// +// m_save +// = new KAction(i18n("Save As..."), +// 0, 0, +// this, SLOT(save()), +// collection, "save_selection"); + + QClipboard *cb = QApplication::clipboard(); + connect(cb, SIGNAL(dataChanged()), 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 parent! + 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(); + + QRect 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 mask. + + for (Q_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) { + QApplication::setOverrideCursor(KisCursor::waitCursor()); + KisPaintLayer *layer = new KisPaintLayer(img, img->nextLayerName() + i18n("(pasted)"), OPACITY_OPAQUE); + Q_CHECK_PTR(layer); + + QRect 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(); + QPoint center = cc->viewToWindow(QPoint(cc->kiscanvas()->width()/2, cc->kiscanvas()->height()/2)); + QPoint bottomright = cc->viewToWindow(QPoint(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 -= QPoint(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() == QDialog::Accepted) + layer->convertTo(img->colorSpace()); +*/ + QApplication::restoreOverrideCursor(); + if(img->addLayer(layer, img->activeLayer()->parent(), img->activeLayer())) + { + return layer; + } else { + return 0; + } + } + return 0; +} + +void KisSelectionManager::pasteNew() +{ + KisPaintDeviceSP clip = m_clipboard->clip(); + if (!clip) return; + + QRect r = clip->exactBounds(); + if (r.width() < 1 && r.height() < 1) { + // Don't paste empty clips + return; + } + + const QCString 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 QString& 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 Q_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; + + QRect rect = selection->selectedRect(); + // Make sure we've got enough space around the edges. + rect = QRect(rect.x() - 3, rect.y() - 3, rect.width() + 6, rect.height() + 6); + rect &= QRect(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 (Q_INT32 xradius, Q_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 + QRect layerSize = dev->exactBounds(); + /* + Any bugs in this fuction are probably also in thin_region + Blame all bugs in this function on jaycox@gimp.org + */ + + Q_UINT8 **buf; // caches the region's pixel data + Q_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 Q_UINT8* [layerSize.width() + 2 * xradius]; + buf = new Q_UINT8* [yradius + 1]; + for (Q_INT32 i = 0; i < yradius + 1; i++) + { + buf[i] = new Q_UINT8[layerSize.width()]; + } + Q_UINT8* buffer = new Q_UINT8[ ( layerSize.width() + 2 * xradius ) * ( yradius + 1 ) ]; + for (Q_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 (Q_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; + + Q_UINT8* out = new Q_UINT8[ layerSize.width() ]; // holds the new scan line we are computing + + Q_INT32* circ = new Q_INT32[ 2 * xradius + 1 ]; // holds the y coords of the filter's mask + 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 (Q_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 (Q_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 (Q_INT32 j = 2; j < yradius + 1; j++) + { + max[x][j] = MAX(buf[j][x], max[x][j-1]); + } + } + + for (Q_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 (Q_INT32 x = 0; x < layerSize.width(); x++) /* update max array */ + { + for (Q_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]; + } + Q_INT32 last_max = max[0][circ[-1]]; + Q_INT32 last_index = 1; + for (Q_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 (Q_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 (Q_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 (Q_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 (Q_INT32 xradius, Q_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 + QRect 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 + */ + Q_UINT8 **buf; // caches the the region's pixels + Q_UINT8 **max; // caches the smallest values for each column + Q_INT32 last_max, last_index; + + if (xradius <= 0 || yradius <= 0) + return; + + max = new Q_UINT8* [layerSize.width() + 2 * xradius]; + buf = new Q_UINT8* [yradius + 1]; + for (Q_INT32 i = 0; i < yradius + 1; i++) + { + buf[i] = new Q_UINT8[layerSize.width()]; + } + + Q_INT32 buffer_size = (layerSize.width() + 2 * xradius + 1) * (yradius + 1); + Q_UINT8* buffer = new Q_UINT8[buffer_size]; + + if (edge_lock) + memset(buffer, 255, buffer_size); + else + memset(buffer, 0, buffer_size); + + for (Q_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 (Q_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; + + Q_UINT8* out = new Q_UINT8[layerSize.width()]; // holds the new scan line we are computing + + Q_INT32* circ = new Q_INT32[2 * xradius + 1]; // holds the y coords of the filter's mask + + computeBorder (circ, xradius, yradius); + + // offset the circ pointer by xradius so the range of the array is [-xradius] to [xradius] + circ += xradius; + + for (Q_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 (Q_INT32 x = 0; x < layerSize.width(); x++) // set up max for top of image + { + max[x][0] = buf[0][x]; + for (Q_INT32 j = 1; j < yradius + 1; j++) + max[x][j] = MIN(buf[j][x], max[x][j-1]); + } + + for (Q_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 (Q_INT32 x = 0 ; x < layerSize.width(); x++) // update max array + { + for (Q_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 (Q_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 (Q_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 (Q_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 (Q_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 mask (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 + QRect layerSize = dev->exactBounds(); + + Q_UINT8 *buf[3]; + + Q_INT32 width = layerSize.width(); + + for (Q_INT32 i = 0; i < 3; i++) buf[i] = new Q_UINT8[width + 2]; + + Q_UINT8* out = new Q_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 (Q_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 (Q_INT32 x = 0 ; x < width; x++) + { + Q_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 (Q_INT32 i = 0; i < 3; i++) + delete[] buf[i]; + + delete[] out; + + dev->setDirty(); + dev->emitSelectionChanged(); +} + +// Erode (radius 1 pixel) a mask (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 + QRect layerSize = dev->exactBounds(); + + Q_UINT8* buf[3]; + + + Q_INT32 width = layerSize.width(); + + for (Q_INT32 i = 0; i < 3; i++) + buf[i] = new Q_UINT8[width + 2]; + + Q_UINT8* out = new Q_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 (Q_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 (Q_INT32 x = 0 ; x < width; x++) + { + Q_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 (Q_INT32 i = 0; i < 3; i++) + delete[] buf[i]; + + delete[] out; + + dev->setDirty(); + dev->emitSelectionChanged(); +} + +// dilate (radius 1 pixel) a mask (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 + QRect layerSize = dev->exactBounds(); + + Q_UINT8* buf[3]; + + Q_INT32 width = layerSize.width(); + + for (Q_INT32 i = 0; i < 3; i++) + buf[i] = new Q_UINT8[width + 2]; + + Q_UINT8* out = new Q_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 (Q_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 (Q_INT32 x = 0 ; x < width; x++) + { + Q_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 (Q_INT32 i = 0; i < 3; i++) + delete[] buf[i]; + + delete[] out; + + dev->setDirty(); + dev->emitSelectionChanged(); +} + +void KisSelectionManager::border(Q_INT32 xradius, Q_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 + QRect layerSize = dev->exactBounds(); + + /* + This function has no bugs, but if you imagine some you can + blame them on jaycox@gimp.org + */ + Q_UINT8 *buf[3]; + Q_UINT8 **density; + Q_UINT8 **transition; + + if (xradius == 1 && yradius == 1) // optimize this case specifically + { + Q_UINT8* source[3]; + + for (Q_INT32 i = 0; i < 3; i++) + source[i] = new Q_UINT8[layerSize.width()]; + + Q_UINT8* transition = new Q_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 (Q_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 (Q_INT32 i = 0; i < 3; i++) + delete[] source[i]; + delete[] transition; + return; + } + + Q_INT32* max = new Q_INT32[layerSize.width() + 2 * xradius]; + for (Q_INT32 i = 0; i < (layerSize.width() + 2 * xradius); i++) + max[i] = yradius + 2; + max += xradius; + + for (Q_INT32 i = 0; i < 3; i++) + buf[i] = new Q_UINT8[layerSize.width()]; + + transition = new Q_UINT8*[yradius + 1]; + for (Q_INT32 i = 0; i < yradius + 1; i++) + { + transition[i] = new Q_UINT8[layerSize.width() + 2 * xradius]; + memset(transition[i], 0, layerSize.width() + 2 * xradius); + transition[i] += xradius; + } + Q_UINT8* out = new Q_UINT8[layerSize.width()]; + density = new Q_UINT8*[2 * xradius + 1]; + density += xradius; + + for (Q_INT32 x = 0; x < (xradius + 1); x++) // allocate density[][] + { + density[ x] = new Q_UINT8[2 * yradius + 1]; + density[ x] += yradius; + density[-x] = density[x]; + } + for (Q_INT32 x = 0; x < (xradius + 1); x++) // compute density[][] + { + double tmpx, tmpy, dist; + Q_UINT8 a; + + if (x > 0) + tmpx = x - 0.5; + else if (x < 0) + tmpx = x + 0.5; + else + tmpx = 0.0; + + for (Q_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 * (Q_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 (Q_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 (Q_INT32 x = 0; x < layerSize.width(); x++) // set up max[] for top of image + { + max[x] = -(yradius + 7); + for (Q_INT32 j = 1; j < yradius + 1; j++) + if (transition[j][x]) + { + max[x] = j; + break; + } + } + for (Q_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 (Q_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; + } + Q_UINT8 last_max = max[0][density[-1]]; + Q_INT32 last_index = 1; + for (Q_INT32 x = 0 ; x < layerSize.width(); x++) // render scan line + { + last_index--; + if (last_index >= 0) + { + last_max = 0; + for (Q_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 (Q_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) + { + Q_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 (Q_INT32 i = 0; i < 3; i++) + delete buf[i]; + + max -= xradius; + delete[] max; + + for (Q_INT32 i = 0; i < yradius + 1; i++) + { + transition[i] -= xradius; + delete transition[i]; + } + delete[] transition; + + for (Q_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 (Q_INT32 *circ, Q_INT32 xradius, Q_INT32 yradius) +{ + Q_ASSERT(xradius != 0); + Q_INT32 i; + Q_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] = (Q_INT32) RINT (yradius / (double) xradius * sqrt (xradius * xradius - tmp * tmp)); + } +} + +void KisSelectionManager::rotatePointers (Q_UINT8 **p, Q_UINT32 n) +{ + Q_UINT32 i; + Q_UINT8 *tmp; + + tmp = p[0]; + + for (i = 0; i < n - 1; i++) p[i] = p[i + 1]; + + p[i] = tmp; +} + +void KisSelectionManager::computeTransition (Q_UINT8* transition, Q_UINT8** buf, Q_INT32 width) +{ + Q_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 (Q_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/krita/ui/kis_selection_manager.h b/krita/ui/kis_selection_manager.h new file mode 100644 index 00000000..7e18a0d9 --- /dev/null +++ b/krita/ui/kis_selection_manager.h @@ -0,0 +1,136 @@ +/* + * 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 "qobject.h" +#include "qptrlist.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 QObject { + + Q_OBJECT + +public: + + KisSelectionManager(KisView * parent, 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 (Q_INT32 xradius, Q_INT32 yradius); + void shrink (Q_INT32 xradius, Q_INT32 yradius, bool edge_lock); + void border(Q_INT32 xradius, Q_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 QString& transactionText); + + void computeBorder (Q_INT32 *circ, Q_INT32 xradius, Q_INT32 yradius); + inline void rotatePointers (Q_UINT8 **p, Q_UINT32 n); + void computeTransition (Q_UINT8* transition, Q_UINT8** buf, Q_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; + + QPtrList m_pluginActions; + +}; + +#endif // KIS_SELECTION_MANAGER_ diff --git a/krita/ui/kis_selection_options.cc b/krita/ui/kis_selection_options.cc new file mode 100644 index 00000000..7d8e62cb --- /dev/null +++ b/krita/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(QWidget *parent, KisCanvasSubject * subject) + : super(parent), + m_subject(subject) +{ + m_page = new WdgSelectionOptions(this); + Q_CHECK_PTR(m_page); + + QVBoxLayout * l = new QVBoxLayout(this); + l->addWidget(m_page); + + connect(m_page->cmbAction, SIGNAL(activated(int)), this, 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/krita/ui/kis_selection_options.h b/krita/ui/kis_selection_options.h new file mode 100644 index 00000000..7b613410 --- /dev/null +++ b/krita/ui/kis_selection_options.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_SELECTION_OPTIONS_H__ +#define __KIS_SELECTION_OPTIONS_H__ + +#include + +#include "koffice_export.h" + +class KisCanvasSubject; +class WdgSelectionOptions; + +/** + */ +class KRITAUI_EXPORT KisSelectionOptions : public QWidget +{ + + Q_OBJECT + + typedef QWidget super; + +public: + KisSelectionOptions( QWidget *parent, 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/krita/ui/kis_text_brush.cc b/krita/ui/kis_text_brush.cc new file mode 100644 index 00000000..6285e503 --- /dev/null +++ b/krita/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() +{ + QFontMetrics metric(m_font); + int w = metric.width(m_txt); + int h = metric.height(); + QPixmap px(w,h); + QPainter p; + p.begin(&px); + p.setFont( m_font ); + p.fillRect(0,0, w, h, Qt::white); + p.setPen(Qt::black); + p.drawText(0, metric.ascent(), m_txt ); + p.end(); + setImage(px.convertToImage ()); +} + +KisTextBrush::KisTextBrush(QWidget *parent, const char* name, const QString& caption) + : KisWdgTextBrush(parent, name), + m_textBrushResource(new KisTextBrushResource()) +{ + setCaption(caption); + connect((QObject*)lineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(rebuildTextBrush())); + connect((QObject*)bnFont, SIGNAL(clicked()), this, SLOT(getFont())); + m_font = font(); + rebuildTextBrush(); +} + + +void KisTextBrush::getFont() +{ + KFontDialog::getFont( m_font, false/*, QWidget* parent! */ ); + rebuildTextBrush(); +} + +void KisTextBrush::rebuildTextBrush() +{ + lblFont->setText(QString(m_font.family() + ", %1").arg(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/krita/ui/kis_text_brush.h b/krita/ui/kis_text_brush.h new file mode 100644 index 00000000..c1cb07c6 --- /dev/null +++ b/krita/ui/kis_text_brush.h @@ -0,0 +1,70 @@ +/* + * 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 QString& txt, const QFont& font) : KisBrush("") + { + setFont(font); + setText(txt); + updateBrush(); + setBrushType(MASK); + }; + public: + virtual bool load() { return false; }; + void setText(const QString& txt) { m_txt = txt; }; + void setFont(const QFont& font) { m_font = font; }; + void updateBrush(); + private: + QFont m_font; + QString m_txt; +}; + +class KisTextBrush : public KisWdgTextBrush +{ + Q_OBJECT +public: + KisTextBrush(QWidget *parent, const char* name, const QString& caption); + +signals: + void activatedResource(KisResource *r); + +private slots: + void rebuildTextBrush(); + void getFont(); + +private: + KisTextBrushResource* m_textBrushResource; + QFont m_font; +}; + + + + +#endif diff --git a/krita/ui/kis_tool.cc b/krita/ui/kis_tool.cc new file mode 100644 index 00000000..7ea39e3c --- /dev/null +++ b/krita/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: + QString uiname; + QLabel * optionWidget; +}; + +KisTool::KisTool(const QString & 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; +} + +QWidget* KisTool::createOptionWidget(QWidget* parent) +{ + + d->optionWidget = new QLabel(i18n("No options for %1.").arg(d->uiname), parent); + d->optionWidget->setCaption(d->uiname); + d->optionWidget->setAlignment(Qt::AlignCenter); + return d->optionWidget; +} + +QWidget* KisTool::optionWidget() +{ + return d->optionWidget; +} + diff --git a/krita/ui/kis_tool.h b/krita/ui/kis_tool.h new file mode 100644 index 00000000..570ec343 --- /dev/null +++ b/krita/ui/kis_tool.h @@ -0,0 +1,143 @@ +/* + * 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 QCursor; +class QEvent; +class QKeyEvent; +class QRect; +class QWidget; +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 shapes 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 Q_UINT8 NUMBER_OF_TOOLTYPES = 6; + +class KisTool : public QObject, public KisCanvasObserver, public KShared { + Q_OBJECT + +public: + KisTool(const QString & name); + virtual ~KisTool(); + +public: + + virtual void paint(KisCanvasPainter& gc) = 0; + virtual void paint(KisCanvasPainter& gc, const QRect& 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(QKeyEvent *e) = 0; + virtual void keyRelease(QKeyEvent *e) = 0; + + virtual QCursor cursor() = 0; + virtual void setCursor(const QCursor& cursor) = 0; + /** + * This function is called to create the configuration widget of the tool. + * @param parent the parent of the widget + */ + virtual QWidget* createOptionWidget(QWidget* parent); + /** + * @return the current configuration widget. + */ + virtual QWidget* 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 Q_UINT32 priority() { return 0; } + virtual enumToolType toolType() { return TOOL_FREEHAND; } + virtual QString icon() { return m_action->icon(); } + virtual QString 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/krita/ui/kis_tool_controller.h b/krita/ui/kis_tool_controller.h new file mode 100644 index 00000000..f135b86e --- /dev/null +++ b/krita/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/krita/ui/kis_tool_dummy.cc b/krita/ui/kis_tool_dummy.cc new file mode 100644 index 00000000..8cb12695 --- /dev/null +++ b/krita/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(QCursor::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", Qt::SHIFT+Qt::Key_H, this, SLOT(activate()), collection, name()); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + + +QWidget* KisToolDummy::createOptionWidget(QWidget* parent) +{ + m_optionWidget = new QLabel(i18n("Layer is locked or invisible."), parent); + m_optionWidget->setCaption(i18n("No Active Tool")); + m_optionWidget->setAlignment(Qt::AlignCenter); + return m_optionWidget; +} + +QWidget* KisToolDummy::optionWidget() +{ + return m_optionWidget; +} + + +#include "kis_tool_dummy.moc" diff --git a/krita/ui/kis_tool_dummy.h b/krita/ui/kis_tool_dummy.h new file mode 100644 index 00000000..3eb57ac4 --- /dev/null +++ b/krita/ui/kis_tool_dummy.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_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 QLabel; +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 + +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 QWidget* createOptionWidget(QWidget* parent); + virtual QWidget* optionWidget(); + +private: + QLabel * m_optionWidget; + KisCanvasSubject *m_subject; + KisPoint m_dragPos; + Q_INT32 m_origScrollX; + Q_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/krita/ui/kis_tool_factory.h b/krita/ui/kis_tool_factory.h new file mode 100644 index 00000000..da1239e3 --- /dev/null +++ b/krita/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/krita/ui/kis_tool_freehand.cc b/krita/ui/kis_tool_freehand.cc new file mode 100644 index 00000000..0909ad9b --- /dev/null +++ b/krita/ui/kis_tool_freehand.cc @@ -0,0 +1,354 @@ +/* + * kis_tool_brush.cc - part of Krita + * + * 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(QString 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() == QMouseEvent::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().contains(e->pos().floorQPoint())) 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(); + + QRect r = m_painter->dirtyRect(); + if ( r.isValid() ) { + m_dirtyRect = r; + + r = QRect(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() == QMouseEvent::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(); + + QRect r = m_painter->dirtyRect(); + + if (r.isValid()) { + m_dirtyRect |= r; + + if (!m_paintOnSelection) { + m_currentImage->activeLayer()->setDirty(r); + } + else { + // Just update the canvas + r = QRect(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->parent() && (l->parent()->parent() == 0) + && (l->parent()->childCount() == 1) + && l->parent()->paintLayerInducesProjectionOptimization(pl)) { + // If there's a mask, device could've been the mask. The induce function + // should catch this, but better safe than sorry + l->parent()->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->parentLayer()); + layer->setTemporaryTarget(0); + m_source->parentLayer()->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().contains(point.floorQPoint())) { + if (m_paintedOutline) { + controller->kiscanvas()->update(); + m_paintedOutline = false; + } + return; + } + + KisCanvas *canvas = controller->kiscanvas(); + canvas->repaint(); + + 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); + QPen pen(Qt::SolidLine); + + KisPoint hotSpot = brush->hotSpot(); + + gc.setRasterOp(Qt::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.roundQPoint(); + } + + gc.translate(topLeft.x(), topLeft.y()); + + KisBoundaryPainter::paint(brush->boundary(), gc); + m_paintedOutline = true; + } +} + + +#include "kis_tool_freehand.moc" + diff --git a/krita/ui/kis_tool_freehand.h b/krita/ui/kis_tool_freehand.h new file mode 100644 index 00000000..1d29a9b7 --- /dev/null +++ b/krita/ui/kis_tool_freehand.h @@ -0,0 +1,102 @@ +/* + * kis_tool_brush.h - part of Krita + * + * 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 + typedef KisToolPaint super; + +public: + KisToolFreehand(const QString 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; + + QString m_transactionText; + enumBrushMode m_mode; + KisPainter *m_painter; + + KisImageSP m_currentImage; +private: + bool m_paintedOutline; +}; + + + +#endif // KIS_TOOL_FREEHAND_H_ + diff --git a/krita/ui/kis_tool_manager.cc b/krita/ui/kis_tool_manager.cc new file mode 100644 index 00000000..66390740 --- /dev/null +++ b/krita/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 * parent, KisCanvasController * controller) + : m_subject(parent), + 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); + + QValueVector inputDevices = KisInputDevice::inputDevices(); + + for (Q_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 parent! + 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(krita::TOOL_OPTION_WIDGET); + } + + if (tool) { + + if (!tool->optionWidget()) { + tool->createOptionWidget(0); + } + QWidget * w = tool->optionWidget(); + + if (w) + m_paletteManager->addWidget(w, krita::TOOL_OPTION_WIDGET, krita::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 QString & 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(SIGNAL(activated()), tool, SLOT(activate())); + } + } + KisTool *oldTool = currentTool(); + if (oldTool) + { + m_paletteManager->removeWidget(krita::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, SIGNAL(activated()), tool, SLOT(activate())); + } +} + +void KisToolManager::activateCurrentTool() +{ + KisTool * t = currentTool(); + if (t && t->action()) { + t->action()->activate(); + } +} + +KisTool * KisToolManager::findTool(const QString &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/krita/ui/kis_tool_manager.h b/krita/ui/kis_tool_manager.h new file mode 100644 index 00000000..d56b16f9 --- /dev/null +++ b/krita/ui/kis_tool_manager.h @@ -0,0 +1,102 @@ +/* + * 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 QObject, public KisToolControllerInterface { + + Q_OBJECT + +public: + + KisToolManager(KisCanvasSubject * parent, 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 QString & toolName); + + virtual KisTool *currentTool() const; + + void setToolForInputDevice(KisInputDevice oldDevice, KisInputDevice newDevice); + + KisTool *findTool(const QString &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/krita/ui/kis_tool_non_paint.cc b/krita/ui/kis_tool_non_paint.cc new file mode 100644 index 00000000..efba4950 --- /dev/null +++ b/krita/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 QString & 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 QRect&) +{ +} + +void KisToolNonPaint::deactivate() +{ +} + +void KisToolNonPaint::buttonPress(KisButtonPressEvent *) +{ +} + +void KisToolNonPaint::move(KisMoveEvent *) +{ +} + +void KisToolNonPaint::buttonRelease(KisButtonReleaseEvent *) +{ +} + +void KisToolNonPaint::doubleClick(KisDoubleClickEvent *) +{ +} + +void KisToolNonPaint::keyPress(QKeyEvent *) +{ +} + +void KisToolNonPaint::keyRelease(QKeyEvent *) +{ +} + +QCursor KisToolNonPaint::cursor() +{ + return m_cursor; +} + +void KisToolNonPaint::setCursor(const QCursor& 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/krita/ui/kis_tool_non_paint.h b/krita/ui/kis_tool_non_paint.h new file mode 100644 index 00000000..21726627 --- /dev/null +++ b/krita/ui/kis_tool_non_paint.h @@ -0,0 +1,84 @@ +/* + * 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 QEvent; +class QKeyEvent; +class QPaintEvent; +class QRect; +class KDialog; +class KisCanvasSubject; + + +class KRITACORE_EXPORT KisToolNonPaint : public KisTool { + + Q_OBJECT + typedef KisTool super; + +public: + KisToolNonPaint(const QString & UIName); + virtual ~KisToolNonPaint(); + +// CanvasObserver +public: + virtual void update(KisCanvasSubject *subject); + +// KisTool +public: + virtual void paint(KisCanvasPainter& gc); + virtual void paint(KisCanvasPainter& gc, const QRect& rc); + + virtual void buttonPress(KisButtonPressEvent *e); + virtual void move(KisMoveEvent *e); + virtual void buttonRelease(KisButtonReleaseEvent *e); + virtual void doubleClick(KisDoubleClickEvent *e); + virtual void keyPress(QKeyEvent *e); + virtual void keyRelease(QKeyEvent *e); + + virtual QCursor cursor(); + virtual void setCursor(const QCursor& cursor); + + virtual enumToolType toolType() { return TOOL_VIEW; } + +public slots: + virtual void activate(); + virtual void deactivate(); + +protected: + void notifyModified() const; + +protected: + KisCanvasSubject *m_subject; + +private: + QCursor m_cursor; +}; + +#endif // KIS_TOOL_NON_PAINT_H_ + diff --git a/krita/ui/kis_tool_paint.cc b/krita/ui/kis_tool_paint.cc new file mode 100644 index 00000000..25129a82 --- /dev/null +++ b/krita/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 QString& 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 QRect&) +{ +} + +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(QKeyEvent *) +{ +} + +void KisToolPaint::keyRelease(QKeyEvent *) +{ +} + +QWidget* KisToolPaint::createOptionWidget(QWidget* parent) +{ + m_optionWidget = new QWidget(parent); + m_optionWidget->setCaption(m_UIName); + + m_lbOpacity = new QLabel(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, SIGNAL(valueChanged(int)), this, SLOT(slotSetOpacity(int))); + + m_lbComposite = new QLabel(i18n("Mode:"), m_optionWidget); + m_cmbComposite = new KisCmbComposite(m_optionWidget); + connect(m_cmbComposite, SIGNAL(activated(const KisCompositeOp&)), this, SLOT(slotSetCompositeMode(const KisCompositeOp&))); + + QVBoxLayout* verticalLayout = new QVBoxLayout(m_optionWidget); + verticalLayout->setMargin(0); + verticalLayout->setSpacing(3); + + m_optionWidgetLayout = new QGridLayout(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 QSpacerItem(0,0,QSizePolicy::Fixed,QSizePolicy::Expanding)); + + if (!quickHelp().isEmpty()) { + QPushButton* push = new QPushButton(SmallIconSet( "help" ), "", m_optionWidget); + connect(push, SIGNAL(clicked()), this, SLOT(slotPopupQuickHelp())); + + QHBoxLayout* hLayout = new QHBoxLayout(m_optionWidget); + hLayout->addWidget(push); + hLayout->addItem(new QSpacerItem(0,0,QSizePolicy::Expanding,QSizePolicy::Fixed)); + verticalLayout->addLayout(hLayout); + } + return m_optionWidget; +} + +QWidget* KisToolPaint::optionWidget() +{ + return m_optionWidget; +} + +void KisToolPaint::addOptionWidgetLayout(QLayout *layout) +{ + Q_ASSERT(m_optionWidget != 0); + Q_ASSERT(m_optionWidgetLayout != 0); + int rowCount = m_optionWidgetLayout->numRows(); + m_optionWidgetLayout->addMultiCellLayout(layout, rowCount, rowCount, 0, 1); +} + +void KisToolPaint::addOptionWidgetOption(QWidget *control, QWidget *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; +} + +QCursor KisToolPaint::cursor() +{ + return m_cursor; +} + +void KisToolPaint::setCursor(const QCursor& 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.find(m_compositeOp) == compositeOps.end()) { + m_compositeOp = COMPOSITE_OVER; + } + m_cmbComposite->setCurrentItem(m_compositeOp); + } + } + } +} + +void KisToolPaint::slotPopupQuickHelp() { + QWhatsThis::display(quickHelp()); +} + +#include "kis_tool_paint.moc" diff --git a/krita/ui/kis_tool_paint.h b/krita/ui/kis_tool_paint.h new file mode 100644 index 00000000..9aae6516 --- /dev/null +++ b/krita/ui/kis_tool_paint.h @@ -0,0 +1,118 @@ +/* + * 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 QCheckBox; +class QEvent; +class QKeyEvent; +class QComboBox; +class QPaintEvent; +class QRect; +class QGridLayout; +class KDialog; +class KisCanvasSubject; +class QLabel; +class KisCmbComposite; +class KisIntSpinbox; + +enum enumBrushMode { + PAINT, + PAINT_STYLUS, + ERASE, + ERASE_STYLUS, + HOVER +}; + +class KRITACORE_EXPORT KisToolPaint : public KisTool { + + Q_OBJECT + typedef KisTool super; + +public: + KisToolPaint(const QString& UIName); + virtual ~KisToolPaint(); + +public: + virtual void update(KisCanvasSubject *subject); + + virtual void paint(KisCanvasPainter& gc); + virtual void paint(KisCanvasPainter& gc, const QRect& rc); + + virtual void buttonPress(KisButtonPressEvent *e); + virtual void move(KisMoveEvent *e); + virtual void buttonRelease(KisButtonReleaseEvent *e); + virtual void doubleClick(KisDoubleClickEvent *e); + virtual void keyPress(QKeyEvent *e); + virtual void keyRelease(QKeyEvent *e); + + virtual QCursor cursor(); + virtual void setCursor(const QCursor& cursor); + virtual QWidget* createOptionWidget(QWidget* parent); + virtual QWidget* optionWidget(); + virtual void addOptionWidgetOption(QWidget *control, QWidget *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 layout to the default option widget's layout. + void addOptionWidgetLayout(QLayout *layout); + +private: + void updateCompositeOpComboBox(); + +protected: + KisCanvasSubject *m_subject; + QRect m_dirtyRect; + Q_UINT8 m_opacity; + KisCompositeOp m_compositeOp; + bool m_paintOutline; + +private: + QString m_UIName; + + QCursor m_cursor; + + QWidget *m_optionWidget; + QGridLayout *m_optionWidgetLayout; + + QLabel *m_lbOpacity; + KisIntSpinbox *m_slOpacity; + QLabel *m_lbComposite; + KisCmbComposite *m_cmbComposite; +}; + +#endif // KIS_TOOL_PAINT_H_ + diff --git a/krita/ui/kis_tool_registry.cc b/krita/ui/kis_tool_registry.cc new file mode 100644 index 00000000..5e5e17d4 --- /dev/null +++ b/krita/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(QString::fromLatin1("Krita/Tool"), + QString::fromLatin1("(Type == 'Service') and " + "([X-Krita-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, QStringList(), &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/krita/ui/kis_tool_registry.h b/krita/ui/kis_tool_registry.h new file mode 100644 index 00000000..2fef3d1e --- /dev/null +++ b/krita/ui/kis_tool_registry.h @@ -0,0 +1,59 @@ +/* + * 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 QStringList; + +/** + * 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 QObject, public KisGenericRegistry{ + + Q_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/krita/ui/kis_tool_shape.cc b/krita/ui/kis_tool_shape.cc new file mode 100644 index 00000000..06c854a7 --- /dev/null +++ b/krita/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 QString& UIName) : super(UIName) +{ + m_shapeOptionsWidget = 0; + m_optionLayout = 0; +} + +KisToolShape::~KisToolShape() +{ +} + +QWidget* KisToolShape::createOptionWidget(QWidget* parent) +{ + QWidget *widget = super::createOptionWidget(parent); + + m_shapeOptionsWidget = new WdgGeometryOptions(0); + Q_CHECK_PTR(m_shapeOptionsWidget); + + m_optionLayout = new QGridLayout(widget, 2, 1); + // super::addOptionWidgetLayout(m_optionLayout); + + m_shapeOptionsWidget->cmbFill->reparent(widget, QPoint(0,0), true); + m_shapeOptionsWidget->textLabel3->reparent(widget, QPoint(0,0), true); + addOptionWidgetOption(m_shapeOptionsWidget->cmbFill, m_shapeOptionsWidget->textLabel3); + + return widget; +} + +KisPainter::FillStyle KisToolShape::fillStyle(void) +{ + if (m_shapeOptionsWidget) { + return static_cast(m_shapeOptionsWidget->cmbFill->currentItem()); + } else { + return KisPainter::FillStyleNone; + } +} + +#include "kis_tool_shape.moc" + diff --git a/krita/ui/kis_tool_shape.h b/krita/ui/kis_tool_shape.h new file mode 100644 index 00000000..b6c1b2db --- /dev/null +++ b/krita/ui/kis_tool_shape.h @@ -0,0 +1,52 @@ +/* + * 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 QGridLayout; +class WdgGeometryOptions; + +class KRITACORE_EXPORT KisToolShape : public KisToolPaint { + + Q_OBJECT + typedef KisToolPaint super; + +public: + KisToolShape(const QString& UIName); + virtual ~KisToolShape(); + + virtual enumToolType toolType() { return TOOL_SHAPE; } + +protected: + virtual QWidget* createOptionWidget(QWidget* parent); + + KisPainter::FillStyle fillStyle(); + +private: + QGridLayout *m_optionLayout; + WdgGeometryOptions *m_shapeOptionsWidget; +}; + +#endif // KIS_TOOL_SHAPE_H_ + diff --git a/krita/ui/kis_tool_types.h b/krita/ui/kis_tool_types.h new file mode 100644 index 00000000..4811f75e --- /dev/null +++ b/krita/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/krita/ui/kis_view.cc b/krita/ui/kis_view.cc new file mode 100644 index 00000000..4bd4a2b1 --- /dev/null +++ b/krita/ui/kis_view.cc @@ -0,0 +1,4018 @@ +/* This file is part of KimageShop^WKrayon^WKrita + * + * 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 + +// Qt +#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, QWidget *parent, const char *name) + : super(doc, parent, 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(parent); + + KisConfig cfg; + + m_currentColorChooserDisplay = KisID("BLA"); + setFocusPolicy( QWidget::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. + qApp->installEventFilter(this); + + m_tabletEventTimer.start(); + m_inputDevice = KisInputDevice::mouse(); + + connect(&m_initialZoomTimer, SIGNAL(timeout()), SLOT(slotInitialZoomTimeout())); + + m_paletteManager = new KoPaletteManager(this, actionCollection(), "Krita palette manager"); + if (cfg.fixDockerWidth()) m_paletteManager->setFixedWidth( 360 ); + + m_paletteManager->createPalette( krita::CONTROL_PALETTE, i18n("Control box")); + m_paletteManager->createPalette( krita::COLORBOX, i18n("Colors")); + m_paletteManager->createPalette( krita::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(Qt::black, cs); + m_bg = KisColor(Qt::white, cs); + + createDockers(); + + setInstance(KisFactory::instance(), false); + setClientBuilder( this ); + + if (!doc->isReadWrite()) + setXMLFile("krita_readonly.rc"); + else + setXMLFile("krita.rc"); + + KStdAction::keyBindings( mainWindow()->guiFactory(), SLOT( configureShortcuts() ), actionCollection() ); + + createLayerBox(); + + setupCanvas(); + m_canvas->hide(); + setupRulers(); + setupScrollBars(); + setupStatusBar(); + + setupActions(); + dcopObject(); + + + connect(this, SIGNAL(autoScroll(const QPoint &)), SLOT(slotAutoScroll(const QPoint &))); + + setMouseTracking(true); + + resetMonitorProfile(); + + layersUpdated(); + + m_brushesAndStuffToolBar = new KisControlFrame(mainWindow(), this); + + // Load all plugins + KTrader::OfferList offers = KTrader::self()->query(QString::fromLatin1("Krita/ViewPlugin"), + QString::fromLatin1("(Type == 'Service') and " + "([X-Krita-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, QStringList(), &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, SIGNAL(loadingFinished()), this, 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 Qt::Dock stringToDock( const QString& attrPosition ) +{ + KToolBar::Dock dock = KToolBar::DockTop; + if ( !attrPosition.isEmpty() ) { + if ( attrPosition == "top" ) + dock = Qt::DockTop; + else if ( attrPosition == "left" ) + dock = Qt::DockLeft; + else if ( attrPosition == "right" ) + dock = Qt::DockRight; + else if ( attrPosition == "bottom" ) + dock = Qt::DockBottom; + else if ( attrPosition == "floating" ) + dock = Qt::DockTornOff; + else if ( attrPosition == "flat" ) + dock = Qt::DockMinimized; + } + return dock; +} + +QWidget * KisView::createContainer( QWidget *parent, int index, const QDomElement &element, int &id ) +{ + if( element.attribute( "name" ) == "ToolBox" ) + { + m_toolBox = new KoToolBox(mainWindow(), "ToolBox", KisFactory::instance(), NUMBER_OF_TOOLTYPES); + m_toolBox->setLabel(i18n("Krita")); + 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( parent, index, element, id ); + +} + +void KisView::removeContainer( QWidget *container, QWidget *parent, QDomElement &element, int id ) +{ + Q_ASSERT(container); + + if( shell() && container == m_toolBox ) + { + delete m_toolBox; + m_toolManager->youAintGotNoToolBox(); + } + else { + KXMLGUIBuilder::removeContainer( container, parent, element, id ); + } +} + +KoPaletteManager * KisView::paletteManager() +{ + if (!m_paletteManager) { + m_paletteManager = new KoPaletteManager(this, actionCollection(), "Krita 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, SIGNAL(sigRequestLayer(KisGroupLayerSP, KisLayerSP)), + this, SLOT(addLayer(KisGroupLayerSP, KisLayerSP))); + connect(m_layerBox, SIGNAL(sigRequestGroupLayer(KisGroupLayerSP, KisLayerSP)), + this, SLOT(addGroupLayer(KisGroupLayerSP, KisLayerSP))); + connect(m_layerBox, SIGNAL(sigRequestAdjustmentLayer(KisGroupLayerSP, KisLayerSP)), + this, SLOT(addAdjustmentLayer(KisGroupLayerSP, KisLayerSP))); + connect(m_layerBox, SIGNAL(sigRequestPartLayer(KisGroupLayerSP, KisLayerSP, const KoDocumentEntry&)), + this, SLOT(addPartLayer(KisGroupLayerSP, KisLayerSP, const KoDocumentEntry&))); + connect(m_layerBox, SIGNAL(sigRequestLayerProperties(KisLayerSP)), + this, SLOT(showLayerProperties(KisLayerSP))); + connect(m_layerBox, SIGNAL(sigOpacityChanged(int, bool)), this, SLOT(layerOpacity(int, bool))); + connect(m_layerBox, SIGNAL(sigOpacityFinishedChanging(int, int)), + this, SLOT(layerOpacityFinishedChanging(int, int))); + connect(m_layerBox, SIGNAL(sigItemComposite(const KisCompositeOp&)), this, SLOT(layerCompositeOp(const KisCompositeOp&))); + + paletteManager()->addWidget(m_layerBox, "layerbox", krita::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 QScrollBar(QScrollBar::Vertical, this); + Q_CHECK_PTR(m_vScroll); + + m_hScroll = new QScrollBar(QScrollBar::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); + QObject::connect(m_vScroll, SIGNAL(valueChanged(int)), this, SLOT(scrollV(int))); + QObject::connect(m_hScroll, SIGNAL(valueChanged(int)), this, 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%").arg(zoom() * 100, 0, 'g', 4)); + } else { + m_statusBarZoomLabel->setText(i18n("Zoom %1%").arg(zoom() * 100, 0, 'f', 0)); + } + m_statusBarZoomLabel->setMaximumWidth(m_statusBarZoomLabel->fontMetrics().width(i18n("Zoom %1%").arg("0.8888 "))); +} + +void KisView::updateStatusBarSelectionLabel() +{ + if (m_statusBarSelectionLabel == 0) { + return; + } + + KisImageSP img = currentImg(); + if (img) { + KisPaintDeviceSP dev = img->activeDevice(); + if (dev) { + if (dev->hasSelection()) { + QRect r = dev->selection()->selectedExactRect(); + m_statusBarSelectionLabel->setText( i18n("Selection Active: x = %1 y = %2 width = %3 height = %4").arg(r.x()).arg(r.y()).arg( r.width()).arg( 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; + QString monitorProfileName = cfg.monitorProfile(); + m_monitorProfile = KisMetaRegistry::instance()->csRegistry()->getProfileByName(monitorProfileName); + } + +} + +void KisView::setupStatusBar() +{ + KStatusBar *sb = statusBar(); + + if (sb) { + m_statusBarZoomLabel = new QLabel(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, SIGNAL( toggled( bool )), this, SLOT( slotUpdateFullScreen( bool ))); + + m_imgProperties = new KAction(i18n("Image Properties"), 0, this, 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, this, SLOT(imgResizeToActiveLayer()), actionCollection(), "resizeimgtolayer"); + + // view actions + m_zoomIn = KStdAction::zoomIn(this, SLOT(slotZoomIn()), actionCollection(), "zoom_in"); + m_zoomOut = KStdAction::zoomOut(this, SLOT(slotZoomOut()), actionCollection(), "zoom_out"); + m_actualPixels = new KAction(i18n("Actual Pixels"), "Ctrl+0", this, SLOT(slotActualPixels()), actionCollection(), "actual_pixels"); + m_actualSize = KStdAction::actualSize(this, SLOT(slotActualSize()), actionCollection(), "actual_size"); + m_actualSize->setEnabled(false); + m_fitToCanvas = KStdAction::fitToPage(this, SLOT(slotFitToCanvas()), actionCollection(), "fit_to_canvas"); + + // layer actions + m_layerAdd = new KAction(i18n("&Add..."), "Ctrl+Shift+N", this, SLOT(layerAdd()), actionCollection(), "insert_layer"); + + m_actionPartLayer = new KoPartSelectAction( i18n( "&Object Layer" ), "frame_query", + this, SLOT( addPartLayer() ), + actionCollection(), "insert_part_layer" ); + + + m_actionAdjustmentLayer = new KAction( i18n( "&Adjustment Layer" ), 0, + this, SLOT( addAdjustmentLayer() ), + actionCollection(), "insert_adjustment_layer" ); + + + m_layerRm = new KAction(i18n("&Remove"), 0, this, SLOT(layerRemove()), actionCollection(), "remove_layer"); + m_layerDup = new KAction(i18n("Duplicate"), 0, this, SLOT(layerDuplicate()), actionCollection(), "duplicate_layer"); + m_layerHide = new KToggleAction(i18n("&Hide"), 0, this, SLOT(layerToggleVisible()), actionCollection(), "hide_layer"); + m_layerHide->setCheckedState(KGuiItem(i18n("&Show"))); + m_layerHide->setChecked(false); + + m_layerRaise = new KAction(i18n("Raise"), "raise", "Ctrl+]", this, SLOT(layerRaise()), actionCollection(), "raiselayer"); + m_layerLower = new KAction(i18n("Lower"), "lower", "Ctrl+[", this, SLOT(layerLower()), actionCollection(), "lowerlayer"); + m_layerTop = new KAction(i18n("To Top"), "bring_forward", "Ctrl+Shift+]", this, SLOT(layerFront()), actionCollection(), "toplayer"); + m_layerBottom = new KAction(i18n("To Bottom"), "send_backward", "Ctrl+Shift+[", this, SLOT(layerBack()), actionCollection(), "bottomlayer"); + m_layerProperties = new KAction(i18n("Properties"), 0, this, SLOT(layerProperties()), actionCollection(), "layer_properties"); + (void)new KAction(i18n("I&nsert Image as Layer..."), 0, this, SLOT(slotInsertImageAsLayer()), actionCollection(), "insert_image_as_layer"); + m_layerSaveAs = new KAction(i18n("Save Layer as Image..."), "filesave", this, SLOT(saveLayerAsImage()), actionCollection(), "save_layer_as_image"); + (void)new KAction(i18n("Flip on &X Axis"), "view_left_right", 0, this, SLOT(mirrorLayerX()), actionCollection(), "mirrorLayerX"); + (void)new KAction(i18n("Flip on &Y Axis"), "view_top_bottom", 0, this, SLOT(mirrorLayerY()), actionCollection(), "mirrorLayerY"); + + m_createMask = new KAction(i18n("Create Mask"), 0, this, + SLOT(slotCreateMask()), actionCollection(), "create_mask"); + m_maskFromSelection = new KAction(i18n("Mask From Selection"), 0, this, + SLOT(slotMaskFromSelection()), actionCollection(), + "mask_fromsel"); + m_maskToSelection = new KAction(i18n("Mask to Selection"), 0, this, + SLOT(slotMaskToSelection()), actionCollection(), "mask_tosel"); + m_applyMask = new KAction(i18n("Apply Mask"), 0, this, SLOT(slotApplyMask()), + actionCollection(), "apply_mask"); + m_removeMask = new KAction(i18n("Remove Mask"), 0, this, + SLOT(slotRemoveMask()), actionCollection(), "remove_mask"); + m_showMask = new KToggleAction(i18n( "Show Mask" ), 0, this, + SLOT(slotShowMask()), actionCollection(), "show_mask"); + m_editMask = new KToggleAction(i18n( "Edit Mask" ), 0, this, + SLOT(slotEditMask()), actionCollection(), "edit_mask"); + + // image actions + m_imgFlatten = new KAction(i18n("&Flatten Image"), "Ctrl+Shift+E", this, SLOT(flattenImage()), actionCollection(), "flatten_image"); + m_imgMergeLayer = new KAction(i18n("&Merge with Layer Below"), "Ctrl+E", this, SLOT(mergeLayer()), actionCollection(), "merge_layer"); + + // setting actions + KStdAction::preferences(this, SLOT(preferences()), actionCollection(), "preferences"); + + m_RulerAction = new KToggleAction( i18n( "Show Rulers" ), "Ctrl+R", this, 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, this, SLOT( viewGuideLines() ), actionCollection(), "view_guidelines" ); + + // Add new palette + new KAction(i18n("Add New Palette..."), 0, this, SLOT(slotAddPalette()), + actionCollection(), "add_palette"); + new KAction(i18n("Edit Palette..."), 0, this, SLOT(slotEditPalette()), + actionCollection(), "edit_palette"); + + // XXX: This triggers a repaint of the image, but way too early + //showRuler(); + +} + +void KisView::resizeEvent(QResizeEvent *) +{ + if (!m_paintViewEnabled) { + startInitialZoomTimerIfReady(); + } + + KisImageSP img = currentImg(); + Q_INT32 scrollBarExtent = style().pixelMetric(QStyle::PM_ScrollBarExtent); + Q_INT32 drawH; + Q_INT32 drawW; + Q_INT32 docW; + Q_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; + } + + Q_INT32 oldCanvasXOffset = m_canvasXOffset; + Q_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() != QSize(drawW, drawH)) { + + Q_INT32 oldCanvasWidth = m_canvasPixmap.width(); + Q_INT32 oldCanvasHeight = m_canvasPixmap.height(); + + Q_INT32 newCanvasWidth = drawW; + Q_INT32 newCanvasHeight = drawH; + + QRegion exposedRegion = QRect(0, 0, newCanvasWidth, newCanvasHeight); + + // Increase size first so that we can copy the old image area to the new one. + m_canvasPixmap.resize(QMAX(oldCanvasWidth, newCanvasWidth), QMAX(oldCanvasHeight, newCanvasHeight)); + + if (!m_canvasPixmap.isNull()) { + + if (oldCanvasXOffset != m_canvasXOffset || oldCanvasYOffset != m_canvasYOffset) { + + Q_INT32 srcX; + Q_INT32 srcY; + Q_INT32 srcWidth; + Q_INT32 srcHeight; + Q_INT32 dstX; + Q_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 -= QRegion(QRect(dstX, dstY, srcWidth, srcHeight)); + } else { + exposedRegion -= QRegion(QRect(0, 0, oldCanvasWidth, oldCanvasHeight)); + } + } + + m_canvasPixmap.resize(newCanvasWidth, newCanvasHeight); + + if (!m_canvasPixmap.isNull() && !exposedRegion.isEmpty()) { + + QMemArray rects = exposedRegion.rects(); + + for (unsigned int i = 0; i < rects.count(); i++) { + QRect r = rects[i]; + updateQPaintDeviceCanvas(viewToWindow(r)); + } + } + } + } + + int fontheight = QFontMetrics(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, QMIN(docW, drawW), m_rulerThickness); + m_vRuler->setGeometry(0, m_rulerThickness + m_canvasYOffset, m_rulerThickness, QMIN(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(QStyle& oldStyle) +{ + Q_UNUSED(oldStyle); + m_canvas->updateGeometry(); + refreshKisCanvas(); +} + +void KisView::paletteChange(const QPalette& oldPalette) +{ + Q_UNUSED(oldPalette); + refreshKisCanvas(); +} + +void KisView::showEvent(QShowEvent *) +{ + if (!m_showEventReceived) { + m_showEventReceived = true; + startInitialZoomTimerIfReady(); + } +} + +void KisView::updateReadWrite(bool readwrite) +{ + layerUpdateGUI(readwrite); +} + +Q_INT32 KisView::horzValue() const +{ + return m_hScroll->value() - m_canvasXOffset; +} + +Q_INT32 KisView::vertValue() const +{ + return m_vScroll->value() - m_canvasYOffset; +} + +void KisView::updateQPaintDeviceCanvas(const QRect& imageRect) +{ + QRect vr = windowToView(imageRect); + vr &= QRect(0, 0, m_canvas->width(), m_canvas->height()); + + if (!vr.isEmpty()) { + + QPainter gc; + + if (gc.begin(&m_canvasPixmap)) { + + KisImageSP img = currentImg(); + + if (img && m_paintViewEnabled) { + + QRect wr = viewToWindow(vr); + + if (wr.left() < 0 || wr.right() >= img->width() || wr.top() < 0 || wr.bottom() >= img->height()) { + // Erase areas outside document + QRegion rg(vr); + rg -= QRegion(windowToView(QRect(0, 0, img->width(), img->height()))); + + QMemArray rects = rg.rects(); + + for (unsigned int i = 0; i < rects.count(); i++) { + QRect er = rects[i]; + gc.fillRect(er, colorGroup().mid()); + } + wr &= QRect(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 { + + QRect canvasRect = windowToView(wr); + QRect scaledImageRect = canvasRect; + scaledImageRect.moveBy(horzValue(), vertValue()); + + QSize scaledImageSize(static_cast(ceil(docWidth() * zoom())), + static_cast(ceil(docHeight() * zoom()))); + + QImage image = m_image->convertToQImage(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, colorGroup().mid()); + } + } + } +} + +void KisView::paintQPaintDeviceView(const QRegion& canvasRegion) +{ + Q_ASSERT(m_canvas->QPaintDeviceWidget() != 0); + + if (m_canvas->QPaintDeviceWidget() != 0 && !m_canvasPixmap.isNull()) { + QMemArray rects = canvasRegion.rects(); + + for (unsigned int i = 0; i < rects.count(); i++) { + QRect r = rects[i]; + + bitBlt(m_canvas->QPaintDeviceWidget(), r.x(), r.y(), &m_canvasPixmap, + r.x(), r.y(), r.width(), r.height()); + } + + paintToolOverlay(canvasRegion); + } +} + +void KisView::updateOpenGLCanvas(const QRect& 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 QRect& canvasRect) +{ +#ifdef HAVE_GL + if (!m_canvas->isUpdatesEnabled()) { + return; + } + + m_canvas->OpenGLWidget()->makeCurrent(); + + glDrawBuffer(GL_BACK); + + QColor widgetBackgroundColor = colorGroup().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) { + + QRect vr = canvasRect; + vr &= QRect(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); + + QRect wr = viewToWindow(QRect(0, 0, m_canvas->width(), m_canvas->height())); + wr &= QRect(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(QRegion(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(Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h) +{ + updateCanvas(QRect(x, y, w, h)); +} + +void KisView::updateCanvas(const QRect& imageRect) +{ + if (m_canvas->isOpenGLCanvas()) { + updateOpenGLCanvas(imageRect); + paintOpenGLView(windowToView(imageRect)); + } else { + updateQPaintDeviceCanvas(imageRect); + //m_canvas->update(windowToView(imageRect)); + m_canvas->repaint(windowToView(imageRect)); + } +} + +void KisView::refreshKisCanvas() +{ + QRect imageRect = viewToWindow(QRect(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->repaint(); +} + +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; + Q_INT32 nlayers = 0; + Q_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; + Q_INT32 scrollX = qRound(x * zoom() - vcx); + m_hScroll->setValue(scrollX); + } + + if (m_vScroll->isVisible()) { + double vcy = m_canvas->height() / 2.0; + Q_INT32 scrollY = qRound(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(QRect(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 QRect& r) +{ + zoomTo(KisRect(r)); +} + +void KisView::zoomTo(Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h) +{ + zoomTo(KisRect(x, y, w, h)); +} + +void KisView::zoomIn(Q_INT32 x, Q_INT32 y) +{ + zoomAroundPoint(x, y, nextZoomInLevel()); +} + +void KisView::zoomOut(Q_INT32 x, Q_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 QMIN(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(); + + QRect 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() == QDialog::Accepted) { + if (dlg.imageWidth() != img->width() || + dlg.imageHeight() != img->height()) { + + resizeCurrentImage(dlg.imageWidth(), + dlg.imageHeight()); + } + Q_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; + } + QValueList resources = srv->resources(); + QValueList 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() != QDialog::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() +{ + QStringList listMimeFilter = KoFilterManager::mimeFilter("application/x-krita", KoFilterManager::Export); + QString mimelist = listMimeFilter.join(" "); + + KFileDialog fd (QString::null, 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(); + QString mimefilter = fd.currentMimeFilter(); + + if (url.isEmpty()) + return; + + + KisImageSP img = currentImg(); + if (!img) return; + + KisLayerSP l = img->activeLayer(); + if (!l) return; + + QRect 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); +} + + + +Q_INT32 KisView::importImage(const KURL& urlArg) +{ + KisImageSP currentImage = currentImg(); + + if (!currentImage) { + return 0; + } + + KURL::List urls; + Q_INT32 rc = 0; + + if (urlArg.isEmpty()) { + QString mimelist = KoFilterManager::mimeFilter("application/x-krita", KoFilterManager::Import).join(" "); + urls = KFileDialog::getOpenURLs(QString::null, 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")); + QRect 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; + Q_INT32 tx = Q_INT32(cx*cos(radians) - cy*sin(radians) - cx + 0.5); + Q_INT32 ty = Q_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->createQPaintDeviceCanvas(); + } + + 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 |= Qt::WindowFullScreen; + } else { + newState &= ~Qt::WindowFullScreen; + } + + KoView::shell()->setWindowState(newState); + } +} + +Q_INT32 KisView::docWidth() const +{ + return currentImg() ? currentImg()->width() : 0; +} + +Q_INT32 KisView::docHeight() const +{ + return currentImg() ? currentImg()->height() : 0; +} + +void KisView::scrollTo(Q_INT32 x, Q_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.toQColor() ); +} + +void KisView::setFGColor(const KisColor& c) +{ + m_fg = c; + notifyObservers(); + emit sigFGQColorChanged( c.toQColor() ); +} + +void KisView::slotSetFGColor(const KisColor& c) +{ + + m_fg = c; + notifyObservers(); +} + +void KisView::slotSetBGColor(const KisColor& c) +{ + + m_bg = c; + notifyObservers(); +} + +void KisView::slotSetFGQColor(const QColor& c) +{ + KisColorSpace * monitorSpace = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA"), m_monitorProfile); + setFGColor(KisColor(c, monitorSpace)); + emit sigFGQColorChanged(c); +} + +void KisView::slotSetBGQColor(const QColor& 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) +{ + QPainter gc(&printer); + + KisImageSP img = currentImg(); + if (!img) return; + + printer.setFullPage(true); + gc.setClipping(false); + + KisConfig cfg; + QString printerProfileName = cfg.printerProfile(); + KisProfile * printerProfile = KisMetaRegistry::instance()->csRegistry() ->getProfileByName(printerProfileName); + + QRect r = img->bounds(); + img->renderToPainter(r.x(), r.y(), r.width(), r.height(), gc, printerProfile, KisImage::PAINT_IMAGE_ONLY, HDRExposure()); +} + +void KisView::paintToolOverlay(const QRegion& 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 repainted + m_toolIsPainting = true; + m_toolManager->currentTool()->paint(gc, region.boundingRect()); + m_toolIsPainting = false; + } +} + +void KisView::canvasGotPaintEvent(QPaintEvent *event) +{ + if (m_canvas->isOpenGLCanvas()) { + paintOpenGLView(event->rect()); + } else { + paintQPaintDeviceView(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) { +// QPoint pt = mapToScreen(e->pos().floorQPoint()); +// KisGuideMgr *mgr = img->guides(); +// +// m_lastGuidePoint = mapToScreen(e->pos().floorQPoint()); +// m_currentGuide = 0; +// +// if ((e->state() & ~Qt::ShiftButton) == Qt::NoButton) { +// KisGuideSP gd = mgr->find(static_cast(pt.x() / zoom()), static_cast(pt.y() / zoom()), QMAX(2.0, 2.0 / zoom())); +// +// if (gd) { +// m_currentGuide = gd; +// +// if ((e->button() == Qt::RightButton) || ((e->button() & Qt::ShiftButton) == Qt::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) { + QPopupMenu * m_popup = 0; + if (factory()) { + Q_ASSERT(factory()); + m_popup = (QPopupMenu *)factory()->container("image_popup", this); + } + if (m_popup) { + m_popup->popup(e->globalPos().roundQPoint()); + } + } + 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) { + QPoint p = mapToScreen(e->pos().floorQPoint()); + 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().floorQPoint()); + 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(QMouseEvent *e) +{ + KisMoveEvent ke(currentInputDevice(), e->pos(), e->globalPos(), PRESSURE_DEFAULT, 0, 0, e->state()); + canvasGotMoveEvent(&ke); +} + +void KisView::slotAutoScroll(const QPoint &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(QEvent *e) +{ + Q_UNUSED( e ); +} + +void KisView::canvasGotLeaveEvent (QEvent *e) +{ + Q_UNUSED( e ); +} + +void KisView::canvasGotMouseWheelEvent(QWheelEvent *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 { + // QApplication::sendEvent(m_vScroll, event); + //} +} + +void KisView::canvasGotKeyPressEvent(QKeyEvent *event) +{ + if (!m_toolManager->currentTool()) { + event->ignore(); + return; + } + + if (event->key() == Qt::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(QKeyEvent *event) +{ + if (m_toolManager->currentTool()) + m_toolManager->currentTool()->keyRelease(event); +} + +void KisView::canvasGotDragEnterEvent(QDragEnterEvent *event) +{ + bool accept = false; + + // Only accept drag if we're not busy, particularly as we may + // be showing a progress bar and calling qApp->processEvents(). + if (KURLDrag::canDecode(event) && QApplication::overrideCursor() == 0) { + accept = true; + } + + event->accept(accept); +} + +void KisView::canvasGotDropEvent(QDropEvent *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(QCursor::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 QStrings are the _serialized_ configs + KisChangeFilterCmd(KisAdjustmentLayerSP layer, + KisFilterConfiguration* config, + const QString& before, + const QString& after) : super(i18n("Change Filter")) + { + m_layer = layer; + m_config = config; + m_before = before; + m_after = after; + } + public: + virtual void execute() + { + QApplication::setOverrideCursor(KisCursor::waitCursor()); + m_config->fromXML(m_after); + //Q_ASSERT(m_after == m_config->toString()); + m_layer->setFilter(m_config); + m_layer->setDirty(); + QApplication::restoreOverrideCursor(); + } + + virtual void unexecute() + { + QApplication::setOverrideCursor(KisCursor::waitCursor()); + m_config->fromXML(m_before); + //Q_ASSERT(m_before == m_config->toString()); + m_layer->setFilter(m_config); + m_layer->setDirty(); + QApplication::restoreOverrideCursor(); + } + private: + KisAdjustmentLayerSP m_layer; + KisFilterConfiguration* m_config; + QString m_before; + QString 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"); + QString before = dlg.filterConfiguration()->toString(); + if (dlg.exec() == QDialog::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() == QDialog::Accepted) + { + if (layer->name() != dlg.getName() || + layer->opacity() != dlg.getOpacity() || + layer->compositeOp() != dlg.getCompositeOp()) + { + QApplication::setOverrideCursor(KisCursor::waitCursor()); + m_adapter->beginMacro(i18n("Property Changes")); + layer->image()->setLayerProperties(layer, dlg.getOpacity(), dlg.getCompositeOp(), dlg.getName()); + layer->setDirty(); + m_adapter->endMacro(); + QApplication::restoreOverrideCursor(); + m_doc->setModified( true ); + } + } + } +} + +void KisView::layerAdd() +{ + KisImageSP img = currentImg(); + if (img && img->activeLayer()) { + addLayer(img->activeLayer()->parent(), img->activeLayer()); + } + else if (img) + addLayer(static_cast(img->rootLayer().data()), 0); +} + +void KisView::addLayer(KisGroupLayerSP parent, KisLayerSP above) +{ + KisImageSP img = currentImg(); + if (img) { + KisConfig cfg; + QString profilename; + if(img->colorSpace()->getProfile()) + profilename = img->colorSpace()->getProfile()->productName(); + NewLayerDialog dlg(img->colorSpace()->id(), profilename, img->nextLayerName(), this); + + if (dlg.exec() == QDialog::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, parent.data(), above); + updateCanvas(); + } else { + KMessageBox::error(this, i18n("Could not add layer to image."), i18n("Layer Error")); + } + } + else { + img->rollBackLayerName(); + } + } +} + +void KisView::addGroupLayer(KisGroupLayerSP parent, KisLayerSP above) +{ + KisImageSP img = currentImg(); + if (img) { + QString 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() == QDialog::Accepted) { + KisLayerSP layer = new KisGroupLayer(img, dlg.layerName(), dlg.opacity()); + if (layer) { + layer->setCompositeOp(dlg.compositeOp()); + img->addLayer(layer, parent.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 parent, KisLayerSP above, const KoDocumentEntry& entry) +{ + delete m_partHandler; // Only one at a time + m_partHandler = new KisPartLayerHandler(this, entry, parent, above); + + disconnect(m_canvas, SIGNAL(sigGotButtonPressEvent(KisButtonPressEvent*)), this, 0); + disconnect(m_canvas, SIGNAL(sigGotButtonReleaseEvent(KisButtonReleaseEvent*)), this, 0); + disconnect(m_canvas, SIGNAL(sigGotMoveEvent(KisMoveEvent*)), this, 0); + disconnect(m_canvas, SIGNAL(sigGotKeyPressEvent(QKeyEvent*)), this, 0); + + connect(m_canvas, SIGNAL(sigGotButtonPressEvent(KisButtonPressEvent*)), + m_partHandler, SLOT(gotButtonPressEvent(KisButtonPressEvent*))); + connect(m_canvas, SIGNAL(sigGotButtonReleaseEvent(KisButtonReleaseEvent*)), + m_partHandler, SLOT(gotButtonReleaseEvent(KisButtonReleaseEvent*))); + connect(m_canvas, SIGNAL(sigGotMoveEvent(KisMoveEvent*)), + m_partHandler, SLOT(gotMoveEvent(KisMoveEvent*))); + connect(m_canvas, SIGNAL(sigGotKeyPressEvent(QKeyEvent*)), + m_partHandler, SLOT(gotKeyPressEvent(QKeyEvent*))); + + connect(m_partHandler, SIGNAL(sigGotMoveEvent(KisMoveEvent*)), + this, SLOT(canvasGotMoveEvent(KisMoveEvent*))); + connect(m_partHandler, SIGNAL(sigGotKeyPressEvent(QKeyEvent*)), + this, SLOT(canvasGotKeyPressEvent(QKeyEvent*))); + connect(m_partHandler, SIGNAL(handlerDone()), + this, SLOT(reconnectAfterPartInsert())); +} + +void KisView::insertPart(const QRect& viewRect, const KoDocumentEntry& entry, + KisGroupLayerSP parent, KisLayerSP above) { + KisImageSP img = currentImg(); + if (!img) return; + + KoDocument* doc = entry.createDoc(m_doc); + if ( !doc ) + return; + + if ( !doc->showEmbedInitDialog(this) ) + return; + + QRect rect = viewToWindow(viewRect); + + KisChildDoc * childDoc = m_doc->createChildDoc(rect, doc); + + KisPartLayerImpl* partLayer = new KisPartLayerImpl(img, childDoc); + partLayer->setDocType(entry.service()->genericName()); + img->addLayer(partLayer, parent, above); + m_doc->setModified(true); + + reconnectAfterPartInsert(); +} + +void KisView::reconnectAfterPartInsert() { + connect(m_canvas, SIGNAL(sigGotButtonPressEvent(KisButtonPressEvent*)), + this, SLOT(canvasGotButtonPressEvent(KisButtonPressEvent*))); + connect(m_canvas, SIGNAL(sigGotButtonReleaseEvent(KisButtonReleaseEvent*)), + this, SLOT(canvasGotButtonReleaseEvent(KisButtonReleaseEvent*))); + connect(m_canvas, SIGNAL(sigGotMoveEvent(KisMoveEvent*)), + this, SLOT(canvasGotMoveEvent(KisMoveEvent*))); + connect(m_canvas, SIGNAL(sigGotKeyPressEvent(QKeyEvent*)), + this, SLOT(canvasGotKeyPressEvent(QKeyEvent*))); + + delete m_partHandler; + m_partHandler = 0; +} + +void KisView::addAdjustmentLayer() +{ + KisImageSP img = currentImg(); + if (!img) return; + + addAdjustmentLayer( img->activeLayer()->parent(), img->activeLayer() ); +} + +void KisView::addAdjustmentLayer(KisGroupLayerSP parent, KisLayerSP above) +{ + Q_ASSERT(parent); + 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() == QDialog::Accepted) { + KisSelectionSP selection = 0; + if (dev->hasSelection()) { + selection = dev->selection(); + } + KisFilterConfiguration * filter = dlg.filterConfiguration(); + QString name = dlg.layerName(); + + addAdjustmentLayer( parent, above, name, filter, selection); + + } +} + +void KisView::addAdjustmentLayer(KisGroupLayerSP parent, KisLayerSP above, const QString & name, + KisFilterConfiguration * filter, KisSelectionSP selection) +{ + Q_ASSERT(parent); + Q_ASSERT(above); + Q_ASSERT(filter); + + KisImageSP img = currentImg(); + if (!img) return; + + KisAdjustmentLayer * l = new KisAdjustmentLayer(img, name, filter, selection); + img->addLayer(l, parent, 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->parent()) + layer->parent()->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'").arg(active->name())); + img->addLayer(dup, active->parent().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(QRect(0, 0, m_canvas->width(), m_canvas->height())); + } else { + QRect drawRect(0, 0, xShift, m_canvasPixmap.height()); + + bitBlt(&m_canvasPixmap, xShift, 0, &m_canvasPixmap, 0, 0, m_canvasPixmap.width() - xShift, m_canvasPixmap.height()); + + updateQPaintDeviceCanvas(viewToWindow(drawRect)); + m_canvas->repaint(); + } + } else if (xShift < 0) { + + QRect drawRect(m_canvasPixmap.width() + xShift, 0, -xShift, m_canvasPixmap.height()); + + if (m_canvas->isOpenGLCanvas()) { + paintOpenGLView(QRect(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()); + + updateQPaintDeviceCanvas(viewToWindow(drawRect)); + m_canvas->repaint(); + } + } + 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(QRect(0, 0, m_canvas->width(), m_canvas->height())); + } else { + QRect drawRect(0, 0, m_canvasPixmap.width(), yShift); + + bitBlt(&m_canvasPixmap, 0, yShift, &m_canvasPixmap, 0, 0, m_canvasPixmap.width(), m_canvasPixmap.height() - yShift); + + updateQPaintDeviceCanvas(viewToWindow(drawRect)); + m_canvas->repaint(); + } + } else if (yShift < 0) { + + if (m_canvas->isOpenGLCanvas()) { + paintOpenGLView(QRect(0, 0, m_canvas->width(), m_canvas->height())); + } else { + QRect 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); + + updateQPaintDeviceCanvas(viewToWindow(drawRect)); + m_canvas->repaint(); + } + } + 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( QWidget::StrongFocus ); + QObject::connect(m_canvas, SIGNAL(sigGotButtonPressEvent(KisButtonPressEvent*)), this, SLOT(canvasGotButtonPressEvent(KisButtonPressEvent*))); + QObject::connect(m_canvas, SIGNAL(sigGotButtonReleaseEvent(KisButtonReleaseEvent*)), this, SLOT(canvasGotButtonReleaseEvent(KisButtonReleaseEvent*))); + QObject::connect(m_canvas, SIGNAL(sigGotDoubleClickEvent(KisDoubleClickEvent*)), this, SLOT(canvasGotDoubleClickEvent(KisDoubleClickEvent*))); + QObject::connect(m_canvas, SIGNAL(sigGotMoveEvent(KisMoveEvent*)), this, SLOT(canvasGotMoveEvent(KisMoveEvent*))); + QObject::connect(m_canvas, SIGNAL(sigGotPaintEvent(QPaintEvent*)), this, SLOT(canvasGotPaintEvent(QPaintEvent*))); + QObject::connect(m_canvas, SIGNAL(sigGotEnterEvent(QEvent*)), this, SLOT(canvasGotEnterEvent(QEvent*))); + QObject::connect(m_canvas, SIGNAL(sigGotLeaveEvent(QEvent*)), this, SLOT(canvasGotLeaveEvent(QEvent*))); + QObject::connect(m_canvas, SIGNAL(sigGotMouseWheelEvent(QWheelEvent*)), this, SLOT(canvasGotMouseWheelEvent(QWheelEvent*))); + QObject::connect(m_canvas, SIGNAL(sigGotKeyPressEvent(QKeyEvent*)), this, SLOT(canvasGotKeyPressEvent(QKeyEvent*))); + QObject::connect(m_canvas, SIGNAL(sigGotKeyReleaseEvent(QKeyEvent*)), this, SLOT(canvasGotKeyReleaseEvent(QKeyEvent*))); + QObject::connect(m_canvas, SIGNAL(sigGotDragEnterEvent(QDragEnterEvent*)), this, SLOT(canvasGotDragEnterEvent(QDragEnterEvent*))); + QObject::connect(m_canvas, SIGNAL(sigGotDropEvent(QDropEvent*)), this, SLOT(canvasGotDropEvent(QDropEvent*))); +} + +void KisView::connectCurrentImg() +{ + if (m_image) { + connect(m_image, SIGNAL(sigActiveSelectionChanged(KisImageSP)), m_selectionManager, SLOT(imgSelectionChanged(KisImageSP))); + connect(m_image, SIGNAL(sigActiveSelectionChanged(KisImageSP)), this, SLOT(updateCanvas())); + connect(m_image, SIGNAL(sigColorSpaceChanged(KisColorSpace *)), this, SLOT(updateStatusBarProfileLabel())); + connect(m_image, SIGNAL(sigProfileChanged(KisProfile * )), SLOT(profileChanged(KisProfile * ))); + + connect(m_image, SIGNAL(sigLayersChanged(KisGroupLayerSP)), SLOT(layersUpdated())); + connect(m_image, SIGNAL(sigMaskInfoChanged()), SLOT(maskUpdated())); + connect(m_image, SIGNAL(sigLayerAdded(KisLayerSP)), SLOT(layersUpdated())); + connect(m_image, SIGNAL(sigLayerRemoved(KisLayerSP, KisGroupLayerSP, KisLayerSP)), SLOT(layersUpdated())); + connect(m_image, SIGNAL(sigLayerMoved(KisLayerSP, KisGroupLayerSP, KisLayerSP)), SLOT(layersUpdated())); + connect(m_image, SIGNAL(sigLayerActivated(KisLayerSP)), SLOT(layersUpdated())); + connect(m_image, SIGNAL(sigLayerActivated(KisLayerSP)), SLOT(updateCanvas())); + connect(m_image, SIGNAL(sigLayerPropertiesChanged(KisLayerSP)), SLOT(layersUpdated())); + + KisConnectPartLayerVisitor v(m_image, this, true); + m_image->rootLayer()->accept(v); + connect(m_image, SIGNAL(sigLayerAdded(KisLayerSP)), + SLOT(handlePartLayerAdded(KisLayerSP))); + + maskUpdated(); +#ifdef HAVE_GL + if (m_OpenGLImageContext != 0) { + connect(m_OpenGLImageContext, SIGNAL(sigImageUpdated(QRect)), SLOT(slotOpenGLImageUpdated(QRect))); + connect(m_OpenGLImageContext, SIGNAL(sigSizeChanged(Q_INT32, Q_INT32)), SLOT(slotImageSizeChanged(Q_INT32, Q_INT32))); + } else +#endif + { + connect(m_image, SIGNAL(sigImageUpdated(QRect)), SLOT(imgUpdated(QRect))); + connect(m_image, SIGNAL(sigSizeChanged(Q_INT32, Q_INT32)), SLOT(slotImageSizeChanged(Q_INT32, Q_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(this, SIGNAL(childActivated(KoDocumentChild*)), + layer, SLOT(childActivated(KoDocumentChild*))); +} + +void KisView::imgUpdated(QRect rc) +{ + updateCanvas(rc); +} + +void KisView::slotOpenGLImageUpdated(QRect rc) +{ + paintOpenGLView(windowToView(rc)); +} + +void KisView::profileChanged(KisProfile * /*profile*/) +{ + updateStatusBarProfileLabel(); +} + +void KisView::slotImageSizeChanged(Q_INT32 /*w*/, Q_INT32 /*h*/) +{ + resizeEvent(0); + refreshKisCanvas(); +} + +void KisView::resizeCurrentImage(Q_INT32 w, Q_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(); +} + + +QPoint KisView::viewToWindow(const QPoint& pt) +{ + QPoint converted; + + converted.rx() = static_cast((pt.x() + horzValue()) / zoom()); + converted.ry() = static_cast((pt.y() + vertValue()) / zoom()); + + return converted; +} + +QPoint KisView::viewToWindow(const QPoint& pt) const +{ + QPoint 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; +} + +QRect KisView::viewToWindow(const QRect& rc) +{ + QRect 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(Q_INT32 *x, Q_INT32 *y) +{ + if (x && y) { + QPoint p = viewToWindow(QPoint(*x, *y)); + *x = p.x(); + *y = p.y(); + } +} + +QPoint KisView::windowToView(const QPoint& pt) +{ + QPoint p; + p.setX(static_cast(pt.x() * zoom() - horzValue())); + p.setY(static_cast(pt.y() * zoom() - vertValue())); + + return p; +} + +QPoint KisView::windowToView(const QPoint& pt) const +{ + QPoint 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; +} + +QRect KisView::windowToView(const QRect& rc) +{ + QRect 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(Q_INT32 *x, Q_INT32 *y) +{ + if (x && y) { + QPoint p = windowToView(QPoint(*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(QObject *o, QEvent *e) +{ + Q_ASSERT(o); + Q_ASSERT(e); + + switch (e->type()) { + case QEvent::TabletMove: + case QEvent::TabletPress: + case QEvent::TabletRelease: + { + QTabletEvent *te = static_cast(e); + KisInputDevice device; + + switch (te->device()) { + default: + case QTabletEvent::Stylus: + case QTabletEvent::NoDevice: + device = KisInputDevice::stylus(); + break; + case QTabletEvent::Puck: + device = KisInputDevice::puck(); + break; + case QTabletEvent::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 receivers that don't accept the tablet event. + m_tabletEventTimer.start(); + break; + } + case QEvent::MouseButtonPress: + case QEvent::MouseMove: + case QEvent::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 QEvent::KeyPress: + case QEvent::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 QEvent::ChildInserted: + { + QChildEvent *childEvent = static_cast(e); + QObject *child = childEvent->child(); + if ( child->isWidgetType() ) { + + child->installEventFilter(this); + + QObjectList *objectList = child->queryList("QWidget"); + QObjectListIt it(*objectList); + QObject *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() == QEvent::MouseMove || e->type() == QEvent::MouseButtonRelease)) { + QMouseEvent *me = dynamic_cast(e); + QPoint pt = mapFromGlobal(me->globalPos()); + KisImageSP img = currentImg(); + KisGuideMgr *mgr; + + if (!img) + return super::eventFilter(o, e); + + mgr = img->guides(); + + if (e->type() == QEvent::MouseMove && (me->state() & Qt::LeftButton)) { + bool flag = geometry().contains(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() == QEvent::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() +//{ +//} + +QPoint KisView::mapToScreen(const QPoint& pt) +{ + QPoint 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; +} + +QCursor KisView::setCanvasCursor(const QCursor & cursor) +{ + QCursor oldCursor = m_canvas->cursor(); + QCursor 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", krita::CONTROL_PALETTE); + + m_hsvwidget = new KoHSVWidget(this, "hsv"); + m_hsvwidget->setCaption(i18n("HSV")); + + connect(m_hsvwidget, SIGNAL(sigFgColorChanged(const QColor &)), this, SLOT(slotSetFGQColor(const QColor &))); + connect(m_hsvwidget, SIGNAL(sigBgColorChanged(const QColor &)), this, SLOT(slotSetBGQColor(const QColor &))); + connect(this, SIGNAL(sigFGQColorChanged(const QColor &)), m_hsvwidget, SLOT(setFgColor(const QColor &))); + connect(this, SIGNAL(sigBGQColorChanged(const QColor &)), m_hsvwidget, SLOT(setBgColor(const QColor &))); + m_paletteManager->addWidget( m_hsvwidget, "hsvwidget", krita::COLORBOX, 0, PALETTE_DOCKER, true); + + m_rgbwidget = new KoRGBWidget(this, "rgb"); + m_rgbwidget->setCaption(i18n("RGB")); + connect(m_rgbwidget, SIGNAL(sigFgColorChanged(const QColor &)), this, SLOT(slotSetFGQColor(const QColor &))); + connect(m_rgbwidget, SIGNAL(sigBgColorChanged(const QColor &)), this, SLOT(slotSetBGQColor(const QColor &))); + connect(this, SIGNAL(sigFGQColorChanged(const QColor &)), m_rgbwidget, SLOT(setFgColor(const QColor &))); + connect(this, SIGNAL(sigBGQColorChanged(const QColor &)), m_rgbwidget, SLOT(setBgColor(const QColor &))); + m_paletteManager->addWidget( m_rgbwidget, "rgbwidget", krita::COLORBOX); + + m_graywidget = new KoGrayWidget(this, "gray"); + m_graywidget->setCaption(i18n("Gray")); + connect(m_graywidget, SIGNAL(sigFgColorChanged(const QColor &)), this, SLOT(slotSetFGQColor(const QColor &))); + connect(m_graywidget, SIGNAL(sigBgColorChanged(const QColor &)), this, SLOT(slotSetBGQColor(const QColor &))); + connect(this, SIGNAL(sigFGQColorChanged(const QColor &)), m_graywidget, SLOT(setFgColor(const QColor &))); + connect(this, SIGNAL(sigBGQColorChanged(const QColor &)), m_graywidget, SLOT(setBgColor(const QColor &))); + m_paletteManager->addWidget( m_graywidget, "graywidget", krita::COLORBOX); + + //make sure the color chooser get right default values + emit sigFGQColorChanged(m_fg.toQColor()); + emit sigBGQColorChanged(m_bg.toQColor()); + + m_palettewidget = new KisPaletteWidget(this); + m_palettewidget->setCaption(i18n("Palettes")); + connect(m_palettewidget, SIGNAL(colorSelected(const QColor &)), + this, SLOT(slotSetFGQColor(const QColor &))); + // No BGColor or reverse slotFGChanged->palette connections, since that's not useful here + + KisResourceServerBase* rServer; + rServer = KisResourceServerRegistry::instance()->get("PaletteServer"); + QValueList resources = rServer->resources(); + QValueList::iterator it; + for ( it = resources.begin(); it != resources.end(); ++it ) { + m_palettewidget->slotAddPalette( *it ); + } + connect(m_palettewidget, SIGNAL(colorSelected(const KisColor &)), this, SLOT(slotSetFGColor(const KisColor &))); + m_paletteManager->addWidget( m_palettewidget, "palettewidget", krita::COLORBOX, 10, PALETTE_DOCKER, true); +} + +QPoint KisView::applyViewTransformations(const QPoint& p) const { + QPoint point(windowToView(p)); + + if (m_hRuler->isShown()) + point.ry() += m_hRuler->height(); + if (m_vRuler -> isShown()) + point.rx() += m_vRuler->width(); + + return point; +} + +QPoint KisView::reverseViewTransformations(const QPoint& 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 + QPoint 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(this, SIGNAL(viewTransformationsChanged()), child, 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(), SIGNAL(loadingFinished()), this, 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->maskFromSelectionCommand(); + 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->maskToSelectionCommand(); + 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::maskUpdated() { + 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_maskFromSelection->setEnabled(true); // Perhaps also update this to false when no selection? + m_maskToSelection->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/krita/ui/kis_view.h b/krita/ui/kis_view.h new file mode 100644 index 00000000..71d97017 --- /dev/null +++ b/krita/ui/kis_view.h @@ -0,0 +1,663 @@ +/* + * 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 QButton; +class QLabel; +class QPaintEvent; +class QScrollBar; +class QWidget; +class QPopup; +class QPopupMenu; + +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 + + typedef KoView super; + + typedef std::list vKisCanvasObserver; + typedef vKisCanvasObserver::iterator vKisCanvasObserver_it; + typedef vKisCanvasObserver::const_iterator vKisCanvasObserver_cit; + +public: + KisView(KisDoc *doc, KisUndoAdapter *adapter, QWidget *parent = 0, const char *name = 0); + virtual ~KisView(); + +public: // KXMLGUIBuilder implementation + + virtual QWidget *createContainer( QWidget *parent, int index, const QDomElement &element, int &id ); + virtual void removeContainer( QWidget *container, QWidget *parent, QDomElement &element, int id ); + +public: // KoView implementation + virtual bool eventFilter(QObject *o, QEvent *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; + + Q_INT32 docWidth() const; + Q_INT32 docHeight() const; + + void updateStatusBarSelectionLabel(); + + virtual QPoint applyViewTransformations(const QPoint& p) const; + virtual QPoint reverseViewTransformations( const QPoint& 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(Q_INT32 xpos, Q_INT32 ypos); + + void sigFGQColorChanged(const QColor &); + void sigBGQColorChanged(const QColor &); + + 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(QMouseEvent *e); + + void resizeCurrentImage(Q_INT32 w, Q_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 QRect& viewRect, const KoDocumentEntry& entry, + KisGroupLayerSP parent, 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 + */ + Q_INT32 importImage(const KURL& url = KURL()); +protected: + + virtual void resizeEvent(QResizeEvent*); // From QWidget + virtual void styleChange(QStyle& oldStyle); // From QWidget + virtual void paletteChange(const QPalette& oldPalette); // From QWidget + virtual void showEvent(QShowEvent *); + +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 Q_INT32 horzValue() const; + virtual Q_INT32 vertValue() const; + + virtual void scrollTo(Q_INT32 x, Q_INT32 y); + + virtual void updateCanvas(Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h); + virtual void updateCanvas(const QRect& imageRect); + + virtual void zoomIn(); + virtual void zoomIn(Q_INT32 x, Q_INT32 y); + + virtual void zoomOut(); + virtual void zoomOut(Q_INT32 x, Q_INT32 y); + + virtual void zoomTo(Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h); + virtual void zoomTo(const QRect& r); + virtual void zoomTo(const KisRect& r); + virtual void zoomAroundPoint(double x, double y, double zf); + + virtual QPoint viewToWindow(const QPoint& pt); + virtual QPoint viewToWindow(const QPoint& pt) const; + virtual KisPoint viewToWindow(const KisPoint& pt); + virtual QRect viewToWindow(const QRect& rc); + virtual KisRect viewToWindow(const KisRect& rc); + virtual void viewToWindow(Q_INT32 *x, Q_INT32 *y); + + virtual QPoint windowToView(const QPoint& pt); + virtual QPoint windowToView(const QPoint& pt) const; + virtual KisPoint windowToView(const KisPoint& pt); + virtual QRect windowToView(const QRect& rc); + virtual KisRect windowToView(const KisRect& rc); + virtual void windowToView(Q_INT32 *x, Q_INT32 *y); + + virtual QCursor setCanvasCursor(const QCursor & 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 QRegion& region); + + void paintQPaintDeviceView(const QRegion& canvasRegion); + void paintOpenGLView(const QRect& canvasRect); + + void updateQPaintDeviceCanvas(const QRect& imageRect); + void updateOpenGLCanvas(const QRect& 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 maskUpdated(); // To update the enabled or disabled status of the mask entries + + void slotSetFGQColor(const QColor & c); + void slotSetBGQColor(const QColor & c); + + void imgUpdated(QRect rc); + void slotOpenGLImageUpdated(QRect rc); + + void imgResizeToActiveLayer(); + + void canvasGotMoveEvent(KisMoveEvent *e); + void canvasGotButtonPressEvent(KisButtonPressEvent *e); + void canvasGotButtonReleaseEvent(KisButtonReleaseEvent *e); + void canvasGotDoubleClickEvent(KisDoubleClickEvent *e); + void canvasGotPaintEvent(QPaintEvent *e); + void canvasGotEnterEvent(QEvent *e); + void canvasGotLeaveEvent(QEvent *e); + void canvasGotMouseWheelEvent(QWheelEvent *e); + void canvasGotKeyPressEvent(QKeyEvent*); + void canvasGotKeyReleaseEvent(QKeyEvent*); + void canvasGotDragEnterEvent(QDragEnterEvent*); + void canvasGotDropEvent(QDropEvent*); + + void reconnectAfterPartInsert(); + + QPoint mapToScreen(const QPoint& 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 parent, KisLayerSP above); + void addGroupLayer(KisGroupLayerSP parent, KisLayerSP above); + void addPartLayer(); + void addPartLayer(KisGroupLayerSP parent, KisLayerSP above, const KoDocumentEntry& entry); + void addAdjustmentLayer(); + void addAdjustmentLayer(KisGroupLayerSP parent, KisLayerSP above); + void addAdjustmentLayer(KisGroupLayerSP parent, KisLayerSP above, const QString & 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(Q_INT32 w, Q_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 QPoint &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; + Q_INT32 m_rulerThickness; + Q_INT32 m_vScrollBarExtent; + Q_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_maskFromSelection; + KAction *m_maskToSelection; + 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 + QScrollBar *m_hScroll; // XXX: the sizing of the scrollthumbs + QScrollBar *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; + + QTimer m_initialZoomTimer; + + +// KisGuideSP m_currentGuide; +// QPoint m_lastGuidePoint; + KisUndoAdapter *m_adapter; + vKisCanvasObserver m_observers; + QLabel *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; + + QTime m_tabletEventTimer; + QTabletEvent::TabletDevice m_lastTabletEventDevice; + + QPixmap 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/krita/ui/kis_view_iface.cc b/krita/ui/kis_view_iface.cc new file mode 100644 index 00000000..7de36c48 --- /dev/null +++ b/krita/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/krita/ui/kis_view_iface.h b/krita/ui/kis_view_iface.h new file mode 100644 index 00000000..0cc9b79d --- /dev/null +++ b/krita/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 Krita 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/krita/ui/kobirdeyepanel.cpp b/krita/ui/kobirdeyepanel.cpp new file mode 100644 index 00000000..fda95945 --- /dev/null +++ b/krita/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, + QWidget * parent, + const char * name, + WFlags f) + : QWidget(parent, name, f) + , m_zoomListener(zoomListener) + , m_thumbnailProvider(thumbnailProvider) + , m_canvas(canvas) + , m_dragging(false) +{ + QHBoxLayout * l = new QHBoxLayout(this); + m_page = new WdgBirdEye(this); + m_page->zoom->setRange((int) (QMAX(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(Qt::NoBackground); + + m_zoomIn = new KAction( i18n("Zoom In"), "birdeye_zoom_plus", 0, this, SLOT(zoomPlus()), this, "zoomIn" ); + m_zoomOut = new KAction( i18n("Zoom Out"), "birdeye_zoom_minus", 0, this, SLOT(zoomMinus()), this, "zoomOut" ); + + l->addWidget(m_page); + + connect(m_page->zoom, SIGNAL(valueChanged(int)), SLOT(zoomValueChanged(int))); + connect(m_page->bn100, SIGNAL(clicked()), SLOT(zoom100())); + connect(m_page->slZoom, SIGNAL(valueChanged(int)), 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(Q_INT32 xpos, Q_INT32 ypos) +{ + m_page->txtX->setText(QString("%L1").arg(xpos, 5)); + m_page->txtY->setText(QString("%L1").arg(ypos, 5)); +} + +void KoBirdEyePanel::setThumbnailProvider(KoThumbnailAdapter * thumbnailProvider) +{ + delete m_thumbnailProvider; + m_thumbnailProvider = thumbnailProvider; +} + +void KoBirdEyePanel::slotViewTransformationChanged() +{ + updateVisibleArea(); + renderView(); + m_page->view->update(); + setZoom(qRound(m_canvas->zoomFactor() * 100)); +} + +void KoBirdEyePanel::slotUpdate(const QRect & r) +{ + QRect updateRect = r; + + if (m_thumbnailProvider->pixelSize() != m_documentSize) { + m_documentSize = m_thumbnailProvider->pixelSize(); + fitThumbnailToView(); + updateRect = QRect(0, 0, m_documentSize.width(), m_documentSize.height()); + } + + updateRect &= QRect(0, 0, m_documentSize.width(), m_documentSize.height()); + + if (!updateRect.isEmpty() && !m_documentSize.isEmpty()) { + + QRect thumbnailRect = documentToThumbnail(KoRect::fromQRect(updateRect)); + + if (!thumbnailRect.isEmpty()) { + + QImage thumbnailImage = m_thumbnailProvider->image(thumbnailRect, m_thumbnail.size()); + + if (!thumbnailImage.isNull()) { + + Q_ASSERT(thumbnailImage.size() == thumbnailRect.size()); + + QPainter painter(&m_thumbnail); + + painter.fillRect(thumbnailRect, colorGroup().mid()); + painter.drawImage(thumbnailRect.x(), thumbnailRect.y(), thumbnailImage); + } + } + } + + renderView(); + m_page->view->update(); +} + +QRect KoBirdEyePanel::documentToThumbnail(const KoRect& docRect) +{ + if (docRect.isEmpty() || m_documentSize.isEmpty() || m_thumbnail.isNull()) { + return QRect(); + } + + Q_INT32 thumbnailLeft = static_cast((docRect.left() * m_thumbnail.width()) / m_documentSize.width()); + Q_INT32 thumbnailRight = static_cast(((docRect.right() + 1) * m_thumbnail.width()) / m_documentSize.width()); + Q_INT32 thumbnailTop = static_cast((docRect.top() * m_thumbnail.height()) / m_documentSize.height()); + Q_INT32 thumbnailBottom = static_cast(((docRect.bottom() + 1) * m_thumbnail.height()) / m_documentSize.height()); + + QRect thumbnailRect(thumbnailLeft, thumbnailTop, thumbnailRight - thumbnailLeft + 1, thumbnailBottom - thumbnailTop + 1); + thumbnailRect &= m_thumbnail.rect(); + + return thumbnailRect; +} + +KoRect KoBirdEyePanel::thumbnailToDocument(const QRect& 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; +} + +QPoint KoBirdEyePanel::viewToThumbnail(const QPoint& viewPoint) +{ + int thumbnailX = (m_viewBuffer.width() - m_thumbnail.width()) / 2; + int thumbnailY = (m_viewBuffer.height() - m_thumbnail.height()) / 2; + + return QPoint(viewPoint.x() - thumbnailX, viewPoint.y() - thumbnailY); +} + + +void KoBirdEyePanel::zoomMinus() +{ +} + +void KoBirdEyePanel::zoomPlus() +{ +} + +void KoBirdEyePanel::updateVisibleArea() +{ + m_visibleAreaInThumbnail = documentToThumbnail(m_canvas->visibleArea()); +} + + +bool KoBirdEyePanel::eventFilter(QObject* o, QEvent* ev) +{ + if (o == m_page->view && ev->type() == QEvent::Resize) { + resizeViewEvent(static_cast(ev)->size()); + } + + if (o == m_page->view && ev->type() == QEvent::Paint) { + paintViewEvent(static_cast(ev)); + } + + if (o == m_page->view && ev->type() == QEvent::MouseMove) { + + QMouseEvent* me = (QMouseEvent*)ev; + QPoint thumbnailPos = viewToThumbnail(me->pos()); + + if (m_dragging) { + handleMouseMoveAction(thumbnailPos); + } else { + handleMouseMove(thumbnailPos); + } + + return true; + } + + if (o == m_page->view && ev->type() == QEvent::MouseButtonPress) { + + QMouseEvent* me = (QMouseEvent*)ev; + QPoint thumbnailPos = viewToThumbnail(me->pos()); + + if (me->button() == LeftButton) { + handleMousePress(thumbnailPos); + } + + return true; + } + + if (o == m_page->view && ev->type() == QEvent::MouseButtonRelease) { + + QMouseEvent* me = (QMouseEvent*)ev; + + if (me->button() == LeftButton) { + m_dragging = false; + } + + return true; + } + + return m_page->eventFilter(o, ev); +} + +KoBirdEyePanel::enumDragHandle KoBirdEyePanel::dragHandleAt(QPoint p) +{ + QRect left = QRect(m_visibleAreaInThumbnail.left()-1, m_visibleAreaInThumbnail.top()-1, 3, m_visibleAreaInThumbnail.height()+2); + QRect right = QRect(m_visibleAreaInThumbnail.right()-1, m_visibleAreaInThumbnail.top()-1, 3, m_visibleAreaInThumbnail.height()+2); + QRect top = QRect(m_visibleAreaInThumbnail.left()-1, m_visibleAreaInThumbnail.top()-1, m_visibleAreaInThumbnail.width()+2, 3); + QRect bottom = QRect(m_visibleAreaInThumbnail.left()-1, m_visibleAreaInThumbnail.bottom()-1, m_visibleAreaInThumbnail.width()+2, 3); + + if (left.contains(p)) { + return DragHandleLeft; + } + + if (right.contains(p)) { + return DragHandleRight; + } + + if (top.contains(p)) { + return DragHandleTop; + } + + if (bottom.contains(p)) { + return DragHandleBottom; + } + + if (m_visibleAreaInThumbnail.contains(p)) { + return DragHandleCentre; + } + + return DragHandleNone; +} + +void KoBirdEyePanel::handleMouseMove(QPoint p) +{ + QCursor cursor; + + switch (dragHandleAt(p)) { + case DragHandleLeft: + case DragHandleRight: + cursor = Qt::sizeHorCursor; + break; + case DragHandleTop: + case DragHandleBottom: + cursor = Qt::sizeVerCursor; + break; + case DragHandleCentre: + cursor = Qt::sizeAllCursor; + break; + default: + case DragHandleNone: + if (m_thumbnail.rect().contains(p)) { + cursor = Qt::PointingHandCursor; + } else { + cursor = Qt::arrowCursor; + } + break; + } + + m_page->view->setCursor(cursor); +} + +void KoBirdEyePanel::handleMouseMoveAction(QPoint p) +{ + if (m_dragging) { + + Q_INT32 dx = p.x() - m_lastDragPos.x(); + Q_INT32 dy = p.y() - m_lastDragPos.y(); + + m_lastDragPos = p; + + QRect 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(QPoint p) +{ + if (!m_dragging) { + + enumDragHandle dragHandle = dragHandleAt(p); + + if (dragHandle == DragHandleNone) { + if (m_thumbnail.rect().contains(p)) { + + // Snap visible area centre to p and begin a centre drag. + + QRect thumbnailRect = m_visibleAreaInThumbnail; + thumbnailRect.moveCenter(p); + makeThumbnailRectVisible(thumbnailRect); + + m_dragHandle = DragHandleCentre; + m_page->view->setCursor(Qt::sizeAllCursor); + m_dragging = true; + } + } else { + m_dragHandle = dragHandle; + m_dragging = true; + } + m_lastDragPos = p; + } +} + +void KoBirdEyePanel::makeThumbnailRectVisible(const QRect& r) +{ + if (r.isEmpty()) { + return; + } + + QRect 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(QSize size) +{ + m_viewBuffer.resize(size); + fitThumbnailToView(); + slotUpdate(QRect(0, 0, m_documentSize.width(), m_documentSize.height())); +} + +void KoBirdEyePanel::fitThumbnailToView() +{ + QRect docRect = QRect(0, 0, m_thumbnailProvider->pixelSize().width(), m_thumbnailProvider->pixelSize().height()); + Q_INT32 thumbnailWidth; + Q_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 = Q_INT32(ceil(docRect.height() * xScale)); + } else { + thumbnailWidth = Q_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(); + + QPainter painter(&m_viewBuffer); + + painter.fillRect(0, 0, m_viewBuffer.width(), m_viewBuffer.height(), colorGroup().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(Qt::red); + painter.drawRect(thumbnailX + m_visibleAreaInThumbnail.x() - 1, + thumbnailY + m_visibleAreaInThumbnail.y() - 1, + m_visibleAreaInThumbnail.width() + 2, + m_visibleAreaInThumbnail.height() + 2); + painter.setPen(Qt::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(QPaintEvent *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/krita/ui/kobirdeyepanel.h b/krita/ui/kobirdeyepanel.h new file mode 100644 index 00000000..0b625c99 --- /dev/null +++ b/krita/ui/kobirdeyepanel.h @@ -0,0 +1,262 @@ +/* + * 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 QPixmap; +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 QRect 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 QSize pixelSize() = 0; + + /** + * Returns the specified rectangle of the thumbnail as a QImage. 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 QImage image(QRect r, QSize 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 QWidget { + + Q_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 parent the parent widget + * @param name the QObject name of this bird eye widget + * @param f the widget flags (@see QWidget) + */ + KoBirdEyePanel( KoZoomAdapter * zoomListener, + KoThumbnailAdapter * thumbnailProvider, + KoCanvasAdapter * canvas, + QWidget * parent, + const char * name = 0, + WFlags f = 0 ); + + virtual ~KoBirdEyePanel(); + + bool eventFilter(QObject*, QEvent*); + +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(Q_INT32 xpos, Q_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 QRect & r); + +protected slots: + + void updateVisibleArea(); + void zoomValueChanged(int zoom); + void zoom100(); + void sliderChanged(int); + +protected: + void setZoom(int zoom); + + void handleMouseMove(QPoint); + void handleMouseMoveAction(QPoint); + void handleMousePress(QPoint); + void fitThumbnailToView(); + void renderView(); + void resizeViewEvent(QSize size); + void paintViewEvent(QPaintEvent *e); + void makeThumbnailRectVisible(const QRect& r); + + enum enumDragHandle { + DragHandleNone, + DragHandleLeft, + DragHandleCentre, + DragHandleRight, + DragHandleTop, + DragHandleBottom + }; + + /* + * Returns the drag handle type at point p in thumbnail coordinates. + */ + enumDragHandle dragHandleAt(QPoint p); + + /** + * Returns the rectangle in the thumbnail covered by the given document rectangle. + */ + QRect documentToThumbnail(const KoRect& docRect); + + /** + * Returns the rectangle in the document covered by the given thumbnail rectangle. + */ + KoRect thumbnailToDocument(const QRect& thumbnailRect); + + /** + * Converts a point in the view to a point in the thumbnail. + */ + QPoint viewToThumbnail(const QPoint& viewPoint); + +private: + + WdgBirdEye * m_page; + + KoZoomAdapter * m_zoomListener; + KoThumbnailAdapter * m_thumbnailProvider; + KoCanvasAdapter * m_canvas; + + KAction* m_zoomIn; + KAction* m_zoomOut; + QPixmap m_viewBuffer; + QPixmap m_thumbnail; + + QSize m_documentSize; + QRect m_visibleAreaInThumbnail; + bool m_dragging; + enumDragHandle m_dragHandle; + QPoint m_lastDragPos; + +}; + +#endif diff --git a/krita/ui/layerlist.cpp b/krita/ui/layerlist.cpp new file mode 100644 index 00000000..5246896d --- /dev/null +++ b/krita/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 QListViewItemIterator +{ +public: + LayerItemIterator( LayerList *list ): QListViewItemIterator( list ) { } + LayerItemIterator( LayerList *list, IteratorFlag flags ): QListViewItemIterator( list, flags ) { } + LayerItemIterator( LayerItem *item ): QListViewItemIterator( item ) { } + LayerItemIterator( LayerItem *item, IteratorFlag flags ): QListViewItemIterator( item, flags ) { } + LayerItem *operator*() { return static_cast( QListViewItemIterator::operator*() ); } +}; + +struct LayerProperty +{ + QString name; + QString displayName; + QPixmap enabledIcon; + QPixmap disabledIcon; + bool defaultValue; + bool validForFolders; + + LayerProperty(): defaultValue( false ), validForFolders( true ) { } + LayerProperty( const QString &pname, const QString &pdisplayName, const QPixmap &enabled, const QPixmap &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; + QValueList properties; + KPopupMenu contextMenu; + LayerToolTip *tooltip; + + Private( QWidget *parent, LayerList *list ); + ~Private(); +}; + +class LayerItem::Private +{ +public: + bool isFolder; + int id; + QValueList properties; + QImage *previewImage; + bool previewChanged; + QPixmap scaledPreview; + QSize previewSize; + QPoint previewOffset; + + Private( int pid ): isFolder( false ), id( pid ), previewImage( 0 ), previewChanged( false ) + { } +}; + +static const int MAX_SIZE = 256; +class LayerToolTip: public QToolTip, public QFrame +{ + LayerList *m_list; + LayerItem *m_item; + QPoint m_pos; + QTimer m_timer; + QImage m_img; + +public: + LayerToolTip( QWidget *parent, LayerList *list ) + : QToolTip( parent ), + QFrame( 0, 0, WStyle_Customize | WStyle_NoBorder | WStyle_Tool | WStyle_StaysOnTop | WX11BypassWM | WNoAutoErase ), + m_list( list ) + { + QFrame::setPalette( QToolTip::palette() ); + connect( &m_timer, SIGNAL( timeout() ), m_list, SLOT( hideTip() ) ); + qApp->installEventFilter( this ); + } + + virtual void maybeTip( const QPoint &pos ) + { + m_pos = pos; + LayerItem *prev = m_item; + m_item = static_cast(m_list->itemAt( m_pos )); + if( QToolTip::parentWidget() && 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() || sizeHint() != size() ) + { + resize( sizeHint() ); + position(); + } + if( !isVisible() ) + show(); + else + update(); + } + + void hideTip() + { + if( !isVisible() ) + return; + QFrame::hide(); + QToolTip::hide(); + m_timer.stop(); + m_img.reset(); + m_list->triggerUpdate(); + } + + virtual void drawContents( QPainter *painter ) + { + QPixmap buf( width(), height() ); + QPainter p( &buf ); + buf.fill( colorGroup().background() ); + p.setPen( colorGroup().foreground() ); + p.drawRect( buf.rect() ); + + QSimpleRichText text( m_item->tooltip(), QToolTip::font() ); + text.setWidth( QCOORD_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, QImage::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(), colorGroup() ); + + painter->drawPixmap( 0, 0, buf ); + } + + virtual QSize sizeHint() const + { + if( !m_item ) + return QSize( 0, 0 ); + + QSimpleRichText text( m_item->tooltip(), QToolTip::font() ); + text.setWidth( QCOORD_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 QSize( width, height ); + } + + void position() + { + const QRect drect = QApplication::desktop()->availableGeometry( QToolTip::parentWidget() ); + const QSize size = sizeHint(); + const int width = size.width(), height = size.height(); + const QRect tmp = m_item->rect(); + const QRect 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(), QToolTip::parentWidget()->mapToGlobal( m_pos ).x() - width/2 ); + if( x + width > drect.right() ) + x = drect.right() - width; + + move( x, y ); + } + + virtual bool eventFilter( QObject *, QEvent *e ) + { + if( isVisible() ) + switch ( e->type() ) + { + case QEvent::KeyPress: + case QEvent::KeyRelease: + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + //case QEvent::MouseMove: + case QEvent::FocusIn: + case QEvent::FocusOut: + case QEvent::Wheel: + case QEvent::Leave: + hideTip(); + default: break; + } + + return false; + } +}; + +LayerList::Private::Private( QWidget *parent, LayerList *list ) + : activeLayer( 0 ), foldersCanBeActive( false ), previewsShown( false ), itemHeight( 32 ), + tooltip( new LayerToolTip( parent, list ) ) { } + +LayerList::Private::~Private() +{ + delete tooltip; + tooltip = 0; +} + +static int getID() +{ + static int id = -2; + return id--; +} + +static QSize iconSize() { return QIconSet::iconSize( QIconSet::Small ); } + + +/////////////// +// LayerList // +/////////////// + +LayerList::LayerList( QWidget *parent, const char *name ) + : super( parent, name ), d( new Private( viewport(), this ) ) +{ + setSelectionMode( QListView::Extended ); + setRootIsDecorated( true ); + setSorting( -1 ); + setSortColumn( -1 ); + setAllColumnsShowFocus( true ); + setFullWidth( true ); + setItemsRenameable( false ); + setDropHighlighter( true ); + setDefaultRenameAction( QListView::Accept ); + setDragEnabled( true ); + setAcceptDrops( true ); + setItemsMovable( true ); + addColumn( QString() ); + header()->hide(); + + QToolTip::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, SIGNAL( itemRenamed( QListViewItem*, const QString&, int ) ), + SLOT( slotItemRenamed( QListViewItem*, const QString&, int ) ) ); + connect( this, SIGNAL( moved( QPtrList&, QPtrList&, QPtrList& ) ), + SLOT( slotItemMoved( QPtrList&, QPtrList&, QPtrList& ) ) ); + connect( this, SIGNAL( onItem( QListViewItem* ) ), SLOT( hideTip() ) ); + connect( this, SIGNAL( onViewport() ), SLOT( hideTip() ) ); +} + +LayerList::~LayerList() +{ + delete d; +} + +void LayerList::addProperty( const QString &name, const QString &displayName, const QIconSet &icon, + bool defaultValue, bool validForFolders ) +{ + addProperty( name, displayName, icon.pixmap( QIconSet::Small, QIconSet::Normal ), icon.pixmap( QIconSet::Small, QIconSet::Disabled ), defaultValue, validForFolders ); +} + +void LayerList::addProperty( const QString &name, const QString &displayName, QPixmap enabled, QPixmap 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; +} + +QValueList LayerList::selectedLayers() const +{ + if( !firstChild() ) + return QValueList(); + + QValueList layers; + for( LayerItemIterator it( firstChild() ); *it; ++it ) + if( (*it)->isSelected() ) + layers.append( *it ); + + return layers; +} + +QValueList LayerList::selectedLayerIDs() const +{ + const QValueList layers = selectedLayers(); + QValueList 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(); +} + +QString LayerList::displayName( int id ) const +{ + LayerItem* const l = layer( id ); + if( !l ) + return QString::null; //should be more severe... + + return l->displayName(); +} + +bool LayerList::property( int id, const QString &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 QString &displayName ) +{ + if( !layer ) + return; + + layer->setDisplayName( displayName ); +} + +void LayerList::setLayerDisplayName( int id, const QString &displayName ) +{ + setLayerDisplayName( layer( id ), displayName ); +} + +void LayerList::setLayerProperty( LayerItem *layer, const QString &name, bool on ) //SLOT +{ + if( !layer ) + return; + + layer->setProperty( name, on ); +} + +void LayerList::setLayerProperty( int id, const QString &name, bool on ) //SLOT +{ + setLayerProperty( layer( id ), name, on ); +} + +void LayerList::toggleLayerProperty( LayerItem *layer, const QString &name ) //SLOT +{ + if( !layer ) + return; + + layer->toggleProperty( name ); +} + +void LayerList::toggleLayerProperty( int id, const QString &name ) //SLOT +{ + toggleLayerProperty( layer( id ), name ); +} + +void LayerList::setLayerPreviewImage( LayerItem *layer, QImage *image ) +{ + if( !layer ) + return; + + layer->setPreviewImage( image ); +} + +void LayerList::setLayerPreviewImage( int id, QImage *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 QString &displayName, LayerItem *after, int id ) //SLOT +{ + return new LayerItem( displayName, this, after, id ); +} + +LayerItem *LayerList::addLayer( const QString &displayName, int afterID, int id ) //SLOT +{ + return new LayerItem( displayName, this, layer( afterID ), id ); +} + +//SLOT +LayerItem *LayerList::addLayerToParent( const QString &displayName, LayerItem *parent, LayerItem *after, int id ) +{ + if( parent && parent->isFolder() ) + return parent->addLayer( displayName, after, id ); + else + return 0; +} + +LayerItem *LayerList::addLayerToParent( const QString &displayName, int parentID, int afterID, int id ) //SLOT +{ + return addLayerToParent( displayName, folder( parentID ), layer( afterID ), id ); +} + +void LayerList::moveLayer( LayerItem *layer, LayerItem *parent, LayerItem *after ) //SLOT +{ + if( !layer ) + return; + + if( parent && !parent->isFolder() ) + parent = 0; + + if( layer->parent() == parent && layer->prevSibling() == after ) + return; + + QListViewItem *current = currentItem(); + + moveItem( layer, parent, after ); + + emit layerMoved( layer, parent, after ); + emit layerMoved( layer->id(), parent ? parent->id() : -1, after ? after->id() : -1 ); + + setCurrentItem( current ); //HACK, sometimes Qt changes this under us +} + +void LayerList::moveLayer( int id, int parentID, int afterID ) //SLOT +{ + moveLayer( layer( id ), folder( parentID ), layer( afterID ) ); +} + +void LayerList::removeLayer( LayerItem *layer ) //SLOT +{ + delete layer; +} + +void LayerList::removeLayer( int id ) //SLOT +{ + delete layer( id ); +} + +void LayerList::contentsMousePressEvent( QMouseEvent *e ) +{ + LayerItem *item = static_cast( itemAt( contentsToViewport( e->pos() ) ) ); + + if( item ) + { + QMouseEvent m( QEvent::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( QMouseEvent *e ) +{ + super::contentsMouseDoubleClickEvent( e ); + if( LayerItem *layer = static_cast( itemAt( contentsToViewport( e->pos() ) ) ) ) + { + if( !layer->iconsRect().contains( 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 QPoint &pos, QListViewItem *&parent, QListViewItem *&after ) +{ + LayerItem *item = static_cast( itemAt( contentsToViewport( pos ) ) ); + if( item && item->isFolder() ) + { + parent = item; + after = 0; + } + else + super::findDrop( pos, parent, after ); +} + +void LayerList::showContextMenu() +{ + LayerItem *layer = static_cast( itemAt( viewport()->mapFromGlobal( QCursor::pos() ) ) ); + if( layer ) + setCurrentItem( layer ); + d->contextMenu.clear(); + constructMenu( layer ); + menuActivated( d->contextMenu.exec( QCursor::pos() ), layer ); +} + +void LayerList::hideTip() +{ + d->tooltip->hideTip(); +} + +void LayerList::maybeTip() +{ + d->tooltip->maybeTip( d->tooltip->QToolTip::parentWidget()->mapFromGlobal( QCursor::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 QValueList selected = selectedLayers(); + + LayerItem *parent = ( layer && layer->isFolder() ) ? layer : 0; + LayerItem *after = 0; + if( layer && !parent ) + { + parent = layer->parent(); + after = layer->prevSibling(); + } + switch( id ) + { + case MenuItems::NewLayer: + emit requestNewLayer( parent, after ); + emit requestNewLayer( parent ? parent->id() : -1, after ? after->id() : -1 ); + break; + case MenuItems::NewFolder: + emit requestNewFolder( parent, after ); + emit requestNewFolder( parent ? parent->id() : -1, after ? after->id() : -1 ); + break; + case MenuItems::RemoveLayer: + { + QValueList 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( QListViewItem *item, const QString &text, int col ) +{ + if( !item || col != 0 ) + return; + + emit displayNameChanged( static_cast( item ), text ); + emit displayNameChanged( static_cast( item )->id(), text ); +} + +void LayerList::slotItemMoved( QPtrList &items, QPtrList &/*afterBefore*/, QPtrList &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->parent() ) + l->parent()->setOpen( true ); + + emit layerMoved( l, l->parent(), a ); + emit layerMoved( l->id(), l->parent() ? l->parent()->id() : -1, a ? a->id() : -1 ); + } +} + +void LayerList::setCurrentItem( QListViewItem *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 QString &displayName, LayerList *p, LayerItem *after, int id ) + : super( p, after ), d( new Private( id ) ) +{ + init(); + setDisplayName( displayName ); +} + +LayerItem::LayerItem( const QString &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( parent()) + parent()->setOpen( true ); +} + +LayerItem::~LayerItem() +{ + if (listView() && (listView()->activeLayer() == this || contains(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::contains(const LayerItem *item) +{ + QListViewItemIterator it(this); + + while (it.current()) { + if (static_cast(it.current()) == item) { + return true; + } + ++it; + } + return false; +} + +int LayerItem::id() const +{ + return d->id; +} + +QString LayerItem::displayName() const +{ + return text( 0 ); +} + +void LayerItem::setDisplayName( const QString &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 QString &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 QString &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 QString &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( QImage *image ) +{ + d->previewImage = image; + previewChanged(); +} + +void LayerItem::previewChanged() +{ + d->previewChanged = true; + update(); +} + +LayerItem *LayerItem::addLayer( const QString &displayName, LayerItem *after, int id ) +{ + if( !isFolder() ) + return 0; + return new LayerItem( displayName, this, after, id ); +} + +LayerItem *LayerItem::prevSibling() const +{ + LayerItem *item = parent() ? parent()->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(); +} + +QPoint LayerItem::mapFromListView( const QPoint &point ) const +{ + return QPoint( mapXFromListView( point.x() ), mapYFromListView( point.y() ) ); +} + +QRect LayerItem::mapFromListView( const QRect &rect ) const +{ + return QRect( 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(); +} + +QPoint LayerItem::mapToListView( const QPoint &point ) const +{ + return QPoint( mapXToListView( point.x() ), mapYToListView( point.y() ) ); +} + +QRect LayerItem::mapToListView( const QRect &rect ) const +{ + return QRect( mapToListView( rect.topLeft() ), rect.size() ); +} + +QRect LayerItem::rect() const +{ + const int indent = listView()->treeStepSize() * ( depth() + 1 ); + return QRect( listView()->header()->sectionPos( 0 ) + indent, itemPos(), + listView()->header()->sectionSize( 0 ) - indent, height() ); +} + +QRect LayerItem::textRect() const +{ + static QFont 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 QRect( indent, 0, width, fontMetrics().height() ); +} + +QRect LayerItem::iconsRect() const +{ + const QValueList &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 QRect( x, y, iconswidth, iconSize().height() ); +} + +QRect LayerItem::previewRect() const +{ + return QRect( 0, 0, listView()->previewsShown() ? height() : 0, height() ); +} + +void LayerItem::drawText( QPainter *p, const QColorGroup &cg, const QRect &r ) +{ + p->translate( r.left(), r.top() ); + + p->setPen( isSelected() ? cg.highlightedText() : cg.text() ); + + const QString text = KStringHandler::rPixelSqueeze( displayName(), p->fontMetrics(), r.width() ); + p->drawText( listView()->itemMargin(), 0, r.width(), r.height(), Qt::AlignAuto | Qt::AlignTop, text ); + + p->translate( -r.left(), -r.top() ); +} + +void LayerItem::drawIcons( QPainter *p, const QColorGroup &/*cg*/, const QRect &r ) +{ + p->translate( r.left(), r.top() ); + + int x = 0; + const QValueList &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( QPainter *p, const QColorGroup &/*cg*/, const QRect &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 QImage i = previewImage()->smoothScale( size, size, QImage::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(); +} + +QFont LayerItem::font() const +{ + if( isActive() ) + { + QFont f = listView()->font(); + f.setBold( !f.bold() ); + f.setItalic( !f.italic() ); + return f; + } + else + return listView()->font(); +} + +QFontMetrics LayerItem::fontMetrics() const +{ + return QFontMetrics( font() ); +} + +bool LayerItem::mousePressEvent( QMouseEvent *e ) +{ + if( e->button() == Qt::RightButton ) + { + if ( !(e->state() & Qt::ControlButton) && !(e->state() & Qt::ShiftButton) ) + setActive(); + QTimer::singleShot( 0, listView(), SLOT( showContextMenu() ) ); + return false; + } + + const QRect ir = iconsRect(), tr = textRect(); + + if( ir.contains( 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 QValueList &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.contains( e->pos() ) && isSelected() && !listView()->renameLineEdit()->isVisible() ) + { + listView()->rename( this, 0 ); + QRect r( listView()->contentsToViewport( mapToListView( tr.topLeft() ) ), tr.size() ); + listView()->renameLineEdit()->setGeometry( r ); + return true; + } + + if ( !(e->state() & Qt::ControlButton) && !(e->state() & Qt::ShiftButton) ) + setActive(); + + return false; +} + +QString LayerItem::tooltip() const +{ + QString tip; + tip += ""; + tip += QString("").arg( displayName() ); + QString 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.arg( i18n( "%1:" ).arg( listView()->d->properties[i].displayName ) ).arg( i18n( "Yes" ) ); + else + tip += row.arg( i18n( "%1:" ).arg( listView()->d->properties[i].displayName ) ).arg( i18n( "No" ) ); + } + tip += "
%1
%1%2
"; + return tip; +} + +QImage *LayerItem::previewImage() const +{ + return d->previewImage; +} + +QImage LayerItem::tooltipPreview() const +{ + if( previewImage() ) + return *previewImage(); + return QImage(); +} + +int LayerItem::width( const QFontMetrics &fm, const QListView *lv, int c ) const +{ + if( c != 0 ) + return super::width( fm, lv, c ); + + const QValueList &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( QPainter *painter, const QColorGroup &cg, int column, int width, int align ) +{ + if( column != 0 ) + { + super::paintCell( painter, cg, column, width, align ); + return; + } + + QPixmap buf( width, height() ); + QPainter p( &buf ); + + p.setFont( font() ); + + const QColorGroup cg_ = isEnabled() ? listView()->palette().active() : listView()->palette().disabled(); + + const QColor 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()->repaintItem( this ); } +LayerItem *LayerItem::firstChild() const { return static_cast( super::firstChild() ); } +LayerItem *LayerItem::nextSibling() const { return static_cast( super::nextSibling() ); } +LayerItem *LayerItem::parent() const { return static_cast( super::parent() ); } + + +#include "layerlist.moc" diff --git a/krita/ui/layerlist.h b/krita/ui/layerlist.h new file mode 100644 index 00000000..b981b266 --- /dev/null +++ b/krita/ui/layerlist.h @@ -0,0 +1,268 @@ +/* + 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 QMouseEvent; +class QString; +class KPopupMenu; +class LayerItem; +class LayerFolder; +template class QPtrList; + +class LayerList: public KListView +{ + Q_OBJECT + +public: + LayerList( QWidget *parent = 0, const char *name = 0 ); + virtual ~LayerList(); + + void addProperty( const QString &name, const QString &displayName, const QIconSet &icon = QIconSet(), + bool defaultValue = false, bool validForFolders = true ); + void addProperty( const QString &name, const QString &displayName, QPixmap enabled, QPixmap 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; + + QValueList selectedLayers() const; + QValueList selectedLayerIDs() const; + + void makeFolder( int id ); + bool isFolder( int id ) const; + QString displayName( int id ) const; + bool property( int id, const QString &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 QString &displayName ); + void setLayerDisplayName( int id, const QString &displayName ); + + void setLayerProperty( LayerItem *layer, const QString &name, bool on ); + void setLayerProperty( int id, const QString &name, bool on ); + + void toggleLayerProperty( LayerItem *layer, const QString &name ); + void toggleLayerProperty( int id, const QString &name ); + + void setLayerPreviewImage( LayerItem *layer, QImage *image ); + void setLayerPreviewImage( int id, QImage *image ); + + void layerPreviewChanged( LayerItem *layer ); + void layerPreviewChanged( int id ); + + LayerItem *addLayer( const QString &displayName, LayerItem *after = 0, int id = -1 ); + LayerItem *addLayer( const QString &displayName, int afterID, int id = -1 ); + + LayerItem *addLayerToParent( const QString &displayName, LayerItem *parent, LayerItem *after = 0, int id = -1 ); + LayerItem *addLayerToParent( const QString &displayName, int parentID, int afterID = -1, int id = -1 ); + + void moveLayer( LayerItem *layer, LayerItem *parent, LayerItem *after ); + void moveLayer( int id, int parentID, int afterID ); + + void removeLayer( LayerItem *layer ); + void removeLayer( int id ); + +signals: + void activated( LayerItem *layer ); + void activated( int id ); + + void displayNameChanged( LayerItem *layer, const QString &displayName ); + void displayNameChanged( int id, const QString &displayName ); + + void propertyChanged( LayerItem *layer, const QString &name, bool on ); + void propertyChanged( int id, const QString &name, bool on ); + + void layerMoved( LayerItem *layer, LayerItem *parent, LayerItem *after ); + void layerMoved( int id, int parentID, int afterID ); + + void requestNewLayer( LayerItem *parent, LayerItem *after ); + void requestNewLayer( int parentID, int afterID ); + + void requestNewFolder( LayerItem *parent, LayerItem *after ); + void requestNewFolder( int parentID, int afterID ); + + void requestRemoveLayer( LayerItem *layer ); + void requestRemoveLayer( int id ); + + void requestRemoveLayers( QValueList layers ); + void requestRemoveLayers( QValueList 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( QListViewItem *item, const QString &text, int col ); + void slotItemMoved( QPtrList&, QPtrList&, QPtrList& ); + void showContextMenu(); + void hideTip(); + void maybeTip(); + +public: //reimplemented for internal reasons + virtual void setCurrentItem( QListViewItem *i ); + +protected: + virtual void contentsMousePressEvent( QMouseEvent *e ); + virtual void contentsMouseDoubleClickEvent ( QMouseEvent *e ); + virtual void findDrop( const QPoint &pos, QListViewItem *&parent, QListViewItem *&after ); +}; + +class LayerItem: public KListViewItem +{ +public: + LayerItem( const QString &displayName, LayerList *parent, LayerItem *after = 0, int id = -1 ); + LayerItem( const QString &displayName, LayerItem *parent, 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 contains(const LayerItem *item); + + int id() const; + + QString displayName() const; + void setDisplayName( const QString &displayName ); + + bool isActive() const; + void setActive(); + + bool property( const QString &name ) const; + void setProperty( const QString &name, bool on ); + void toggleProperty( const QString &name ); + + void setPreviewImage( QImage *image ); + void previewChanged(); + + LayerItem *addLayer( const QString &displayName, LayerItem *after = 0, int id = -1 ); + + LayerItem *prevSibling() const; + +public: //convenience + LayerItem *nextSibling() const; + LayerList *listView() const; + LayerItem *firstChild() const; + LayerItem *parent() const; + void update() const; //like QWidget::update() + +protected: + virtual QRect rect() const; + + int mapXFromListView( int x ) const; + int mapYFromListView( int y ) const; + QPoint mapFromListView( const QPoint &point ) const; + QRect mapFromListView( const QRect &rect ) const; + + int mapXToListView( int x ) const; + int mapYToListView( int y ) const; + QPoint mapToListView( const QPoint &point ) const; + QRect mapToListView( const QRect &rect ) const; + + virtual QRect textRect() const; + virtual QRect iconsRect() const; + virtual QRect previewRect() const; + + virtual void drawText( QPainter *p, const QColorGroup &cg, const QRect &r ); + virtual void drawIcons( QPainter *p, const QColorGroup &cg, const QRect &r ); + virtual void drawPreview( QPainter *p, const QColorGroup &cg, const QRect &r ); + + bool multiline() const; + bool showPreview() const; + virtual QFont font() const; + QFontMetrics fontMetrics() const; + + virtual bool mousePressEvent( QMouseEvent *e ); + + virtual QString tooltip() const; + + virtual QImage *previewImage() const; + virtual QImage 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 QFontMetrics &fm, const QListView *lv, int c ) const; + virtual void paintCell( QPainter *p, const QColorGroup &cg, int column, int width, int align ); + virtual void setup(); + virtual void setSelected( bool selected ); +}; + +class LayerFolder: public LayerItem +{ +public: + LayerFolder( const QString &displayName, LayerList *parent, LayerItem *after = 0, int id = -1 ) + : LayerItem( displayName, parent, after, id ) { makeFolder(); } + LayerFolder( const QString &displayName, LayerItem *parent, LayerItem *after = 0, int id = -1 ) + : LayerItem( displayName, parent, after, id ) { makeFolder(); } +}; + + +#endif diff --git a/krita/ui/squeezedcombobox.cpp b/krita/ui/squeezedcombobox.cpp new file mode 100644 index 00000000..971a73e6 --- /dev/null +++ b/krita/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 */ + +// Qt includes. + +#include +#include +#include +#include +#include +#include +#include +#include + +// Local includes. + +#include "squeezedcombobox.h" + +SqueezedComboBoxTip::SqueezedComboBoxTip( QWidget * parent, SqueezedComboBox* name ) + : QToolTip( parent ) +{ + m_originalWidget = name; +} + +void SqueezedComboBoxTip::maybeTip( const QPoint &pos ) +{ + QListBox* listBox = m_originalWidget->listBox(); + if (!listBox) + return; + + QListBoxItem* selectedItem = listBox->itemAt( pos ); + if (selectedItem) + { + QRect positionToolTip = listBox->itemRect( selectedItem ); + QString toolTipText = m_originalWidget->itemHighlighted(); + if (!toolTipText.isNull()) + tip(positionToolTip, toolTipText); + } +} + +SqueezedComboBox::SqueezedComboBox( QWidget *parent, const char *name ) + : QComboBox( parent, name ) +{ + setMinimumWidth(100); + m_timer = new QTimer(this); + m_tooltip = new SqueezedComboBoxTip( listBox()->viewport(), this ); + + connect(m_timer, SIGNAL(timeout()), + SLOT(slotTimeOut())); + connect(this, SIGNAL(activated( int )), + SLOT(slotUpdateToolTip( int ))); +} + +SqueezedComboBox::~SqueezedComboBox() +{ + delete m_tooltip; + delete m_timer; +} + +bool SqueezedComboBox::contains( const QString& _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; +} + +QSize SqueezedComboBox::sizeHint() const +{ + constPolish(); + QFontMetrics fm = fontMetrics(); + + int maxW = count() ? 18 : 7 * fm.width(QChar('x')) + 18; + int maxH = QMAX( fm.lineSpacing(), 14 ) + 2; + + return style().sizeFromContents(QStyle::CT_ComboBox, this, + QSize(maxW, maxH)). + expandedTo(QApplication::globalStrut()); +} + +void SqueezedComboBox::insertSqueezedItem(const QString& 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 ( QResizeEvent * ) +{ + m_timer->start(200, true); +} + +void SqueezedComboBox::slotTimeOut() +{ + QMapIterator it; + for (it = m_originalItems.begin() ; it != m_originalItems.end(); + ++it) + { + changeItem( squeezeText( it.data() ), it.key() ); + } +} + +QString SqueezedComboBox::squeezeText( const QString& original) +{ + // not the complete widgetSize is usable. Need to compensate for that. + int widgetSize = width()-30; + QFontMetrics fm( fontMetrics() ); + + // If we can fit the full text, return that. + if (fm.width(original) < widgetSize) + return(original); + + // We need to squeeze. + QString 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 = QString("..." + original.right(--i)); + break; + } + } + return sqItem; +} + +void SqueezedComboBox::slotUpdateToolTip( int index ) +{ + QToolTip::remove(this); + QToolTip::add(this, m_originalItems[index]); +} + +QString SqueezedComboBox::itemHighlighted() +{ + int curItem = this->listBox()->currentItem(); + return m_originalItems[curItem]; +} + +#include "squeezedcombobox.moc" diff --git a/krita/ui/squeezedcombobox.h b/krita/ui/squeezedcombobox.h new file mode 100644 index 00000000..51f9eb51 --- /dev/null +++ b/krita/ui/squeezedcombobox.h @@ -0,0 +1,136 @@ +/* ============================================================ + * 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 SQUEEZEDCOMBOBOX_H +#define SQUEEZEDCOMBOBOX_H + +class QTimer; + +// Qt 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 QToolTip + * + * @author Tom Albers + */ +class SqueezedComboBoxTip : public QToolTip +{ +public: + /** + * Constructor. An example call (as done in + * SqueezedComboBox::SqueezedComboBox): + * @code + * t = new SqueezedComboBoxTip( this->listBox()->viewport(), this ); + * @endcode + * + * @param parent parent widget (viewport) + * @param name parent widget + */ + SqueezedComboBoxTip( QWidget *parent, SqueezedComboBox *name ); + +protected: + /** + * Reimplemented version from QToolTip which shows the + * tooltip when needed. + * @param pos the point where the mouse currently is + */ + void maybeTip( const QPoint& pos ); + +private: + SqueezedComboBox* m_originalWidget; +}; + +/** @class SqueezedComboBox + * + * This widget is a QComboBox, 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 QComboBox +{ + Q_OBJECT + +public: + /** + * Constructor + * @param parent parent widget + * @param name name to give to the widget + */ + SqueezedComboBox(QWidget *parent = 0, const char *name = 0 ); + + /** + * destructor + */ + virtual ~SqueezedComboBox(); + + bool contains(const QString & text) const; + + /** + * This inserts a item to the list. See QComboBox::insertItem() + * for detaills. Please do not use QComboBox::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 QString& newItem, int index); + + /** + * This method returns the full text (not squeezed) of the currently + * highlighted item. + * @return full text of the highlighted item + */ + QString itemHighlighted( ); + + /** + * Sets the sizeHint() of this widget. + */ + virtual QSize sizeHint() const; + +private slots: + void slotTimeOut(); + void slotUpdateToolTip( int index ); + +private: + void resizeEvent ( QResizeEvent * ); + QString squeezeText( const QString& original); + + QMap m_originalItems; + QTimer* m_timer; + SqueezedComboBoxTip* m_tooltip; +}; + +#endif // SQUEEZEDCOMBOBOX_H diff --git a/krita/ui/wdgapplyprofile.ui b/krita/ui/wdgapplyprofile.ui new file mode 100644 index 00000000..f486b625 --- /dev/null +++ b/krita/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, Krita 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/krita/ui/wdgautobrush.ui b/krita/ui/wdgautobrush.ui new file mode 100644 index 00000000..dd6b55fc --- /dev/null +++ b/krita/ui/wdgautobrush.ui @@ -0,0 +1,355 @@ + +KisWdgAutobrush + + + KisWdgAutobrush + + + + 0 + 0 + 373 + 200 + + + + + 1 + 1 + 0 + 0 + + + + + unnamed + + + + layout3 + + + + unnamed + + + + grpSize + + + &Size + + + + unnamed + + + 0 + + + + layout21 + + + + 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 + + + + layout23 + + + + 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 + + + + + + + + + layout6 + + + + unnamed + + + + brushPreview + + + + 7 + 7 + 0 + 0 + + + + + 95 + 95 + + + + + + + true + + + + + + Circle + + + + + Square + + + + comboBoxShape + + + ClickFocus + + + + + spacer4 + + + Vertical + + + Expanding + + + + 20 + 0 + + + + + + + + + + 89504e470d0a1a0a0000000d49484452000000190000001a0806000000427df7cd000000b3494441544889dd963112c420084581d97acdfd4f29b9005b3913135050d722bf54f0018223e6ccf06f7db4c594be4d27e63304a190f525885e20154433f646ea050d6512d516887af10075c922f5d7e4ca24da4d439059f803721c4946a1962f798c6641d4da5c05421101445c06b82a6746804d73822202cc67956289a0c89a937b77596790b638abfb59d4da5c017840664196aff97679deab62d39bfcf73cf5ef8160ef4bb4e2e7627657e4909eb694eb071e3b4da9ba4f1ddb0000000049454e44ae426082 + + + 89504e470d0a1a0a0000000d49484452000000190000001a0806000000427df7cd000000b9494441544889dd95410ec4200845b1e9ba78ff538a176056260c5181569bccfca590ff2a204da510ecd601008078ed8778953372cec8db20d23c0a72417aa611900999997941a795500a256d2acf7a434354bf212d4927ebc488a417518d4dd75d0dcbb5f2ed983d59f101af94eb7f20d39e3c1963136299f7e2b361f89d9e8c6ed16efc4ee3892a205ecb9adc24fdcc176ffd4b9839e9b896592eb9d623b1106464e605b821da340200086e61afb91ea2a377e89577e57f00357f504513c00b590000000049454e44ae426082 + + + + diff --git a/krita/ui/wdgautogradient.ui b/krita/ui/wdgautogradient.ui new file mode 100644 index 00000000..ab2821c8 --- /dev/null +++ b/krita/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 + + + + + layout11 + + + + Arial Unicode MS + 6 + + + + + unnamed + + + + layout10 + + + + + + + + unnamed + + + + textLabel1 + + + + + + + Segment Color + + + + + layout8 + + + + + + + + unnamed + + + + labelLeftColor + + + + + + + Left: + + + + + leftColorButton + + + + 0 + 0 + 0 + 0 + + + + + 30 + 30 + + + + + + + + ClickFocus + + + + + + + + + + layout9 + + + + + + + + unnamed + + + + labelRightColor + + + + + + + Right: + + + + + rightColorButton + + + + 0 + 0 + 0 + 0 + + + + + 30 + 30 + + + + + + + + ClickFocus + + + + + + + + + + + + layout5 + + + + + + + + unnamed + + + + textLabel2 + + + + + + + Opacity: + + + + + intNumInputLeftOpacity + + + + 5 + 0 + 0 + 0 + + + + + + + + ClickFocus + + + % + + + 100 + + + + + intNumInputRightOpacity + + + + 5 + 0 + 0 + 0 + + + + + + + + ClickFocus + + + % + + + 100 + + + + + + + + + layout11_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/krita/ui/wdgbirdeye.ui b/krita/ui/wdgbirdeye.ui new file mode 100644 index 00000000..0333ef7a --- /dev/null +++ b/krita/ui/wdgbirdeye.ui @@ -0,0 +1,304 @@ + +WdgBirdEye + + + WdgBirdEye + + + + 0 + 0 + 188 + 126 + + + + + 1 + 1 + 0 + 0 + + + + Overview + + + + + + + + unnamed + + + 0 + + + 0 + + + + layout4 + + + + unnamed + + + 1 + + + 1 + + + + layout10 + + + + 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 + + + + + + layout4 + + + + 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/krita/ui/wdgcolorsettings.ui b/krita/ui/wdgcolorsettings.ui new file mode 100644 index 00000000..63034d50 --- /dev/null +++ b/krita/ui/wdgcolorsettings.ui @@ -0,0 +1,357 @@ + +WdgColorSettings + + + WdgColorSettings + + + + 0 + 0 + 586 + 457 + + + + Color Settings + + + + unnamed + + + + layout8 + + + + 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 + + + + + + + layout6 + + + + 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/krita/ui/wdgcustombrush.ui b/krita/ui/wdgcustombrush.ui new file mode 100644 index 00000000..ea0418b3 --- /dev/null +++ b/krita/ui/wdgcustombrush.ui @@ -0,0 +1,199 @@ + +KisWdgCustomBrush + + + KisWdgCustomBrush + + + + 0 + 0 + 267 + 265 + + + + + unnamed + + + + layout4 + + + + unnamed + + + + textLabel2 + + + Style: + + + + + + Constant + + + + + Random + + + + + Incremental + + + + + Pressure + + + + + Angular + + + + comboBox2 + + + true + + + 2 + + + + + textLabel3 + + + Selection mode: + + + + + + Regular + + + + + Animated + + + + style + + + + + + + colorAsMask + + + Use color as mask + + + + + layout6 + + + + unnamed + + + + spacer2 + + + Horizontal + + + Expanding + + + + 40 + 20 + + + + + + preview + + + + 0 + 0 + 0 + 0 + + + + + 50 + 50 + + + + + + + + + spacer1 + + + Horizontal + + + Expanding + + + + 40 + 20 + + + + + + + + layout7 + + + + unnamed + + + + brushButton + + + Use as Brush + + + + + addButton + + + Add to Predefined Brushes + + + + + + + + diff --git a/krita/ui/wdgcustompalette.ui b/krita/ui/wdgcustompalette.ui new file mode 100644 index 00000000..251a51bb --- /dev/null +++ b/krita/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/krita/ui/wdgcustompattern.ui b/krita/ui/wdgcustompattern.ui new file mode 100644 index 00000000..9db08918 --- /dev/null +++ b/krita/ui/wdgcustompattern.ui @@ -0,0 +1,156 @@ + +KisWdgCustomPattern + + + KisWdgCustomPattern + + + + 0 + 0 + 255 + 232 + + + + + unnamed + + + + layout4 + + + + unnamed + + + + textLabel1 + + + Source: + + + + + + Entire Image + + + + comboBox1 + + + false + + + + + + + layout6 + + + + unnamed + + + + spacer2 + + + Horizontal + + + Expanding + + + + 40 + 20 + + + + + + preview + + + + 0 + 0 + 0 + 0 + + + + + 50 + 50 + + + + + + + + + spacer1 + + + Horizontal + + + Expanding + + + + 40 + 20 + + + + + + + + layout7 + + + + unnamed + + + + patternButton + + + Use as Pattern + + + + + exportButton + + + false + + + Export + + + + + addButton + + + Add to Predefined Patterns + + + + + + + + diff --git a/krita/ui/wdgdisplaysettings.ui b/krita/ui/wdgdisplaysettings.ui new file mode 100644 index 00000000..1427a497 --- /dev/null +++ b/krita/ui/wdgdisplaysettings.ui @@ -0,0 +1,90 @@ + +WdgDisplaySettings + + + WdgDisplaySettings + + + + 0 + 0 + 374 + 154 + + + + Display + + + + unnamed + + + + spacer3 + + + Vertical + + + Expanding + + + + 20 + 50 + + + + + + buttonGroup1 + + + OpenGL + + + + unnamed + + + + layout4 + + + + unnamed + + + + cbUseOpenGL + + + Enable OpenGL + + + + + + + spacer4 + + + Horizontal + + + Expanding + + + + 121 + 31 + + + + + + + + + diff --git a/krita/ui/wdggeneralsettings.ui b/krita/ui/wdggeneralsettings.ui new file mode 100644 index 00000000..35864b49 --- /dev/null +++ b/krita/ui/wdggeneralsettings.ui @@ -0,0 +1,183 @@ + +WdgGeneralSettings + + + WdgGeneralSettings + + + + 0 + 0 + 335 + 209 + + + + + unnamed + + + + layout3 + + + + unnamed + + + + layout1 + + + + unnamed + + + + textLabel1 + + + &Cursor shape: + + + m_cmbCursorShape + + + + + + Tool Icon + + + + + Crosshair + + + + + Arrow + + + + + Brush Outline + + + + m_cmbCursorShape + + + + + + + grpDockability + + + Palette Behavior + + + true + + + + unnamed + + + + radioAllowDocking + + + Allow &docking + + + + + radioDisallowDocking + + + Allow only &floating + + + + + radioSmartDocking + + + Allow docking only on &large screens + + + + + + + layout2 + + + + unnamed + + + + textLabel1_2 + + + &Palette font size: + + + numDockerFontSize + + + + + numDockerFontSize + + + + + + + + + spacer1 + + + Horizontal + + + Expanding + + + + 41 + 20 + + + + + + spacer2 + + + Vertical + + + Expanding + + + + 20 + 41 + + + + + + + + + + knuminput.h + + diff --git a/krita/ui/wdggridsettings.ui b/krita/ui/wdggridsettings.ui new file mode 100644 index 00000000..77515844 --- /dev/null +++ b/krita/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 + + + + layout8 + + + + unnamed + + + + layout6 + + + + 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 + + + + + + + layout9 + + + + 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/krita/ui/wdglayerbox.ui b/krita/ui/wdglayerbox.ui new file mode 100644 index 00000000..a384f306 --- /dev/null +++ b/krita/ui/wdglayerbox.ui @@ -0,0 +1,299 @@ + +WdgLayerBox + + + WdgLayerBox + + + + 0 + 0 + 352 + 542 + + + + + unnamed + + + 0 + + + 0 + + + + layout3 + + + + unnamed + + + + cmbComposite + + + + 3 + 0 + 0 + 0 + + + + + 0 + 10 + + + + Blending mode + + + + + intOpacity + + + + 0 + 5 + 0 + 0 + + + + + + + + listLayers + + + + + layout6 + + + + 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/krita/ui/wdglayerproperties.ui b/krita/ui/wdglayerproperties.ui new file mode 100644 index 00000000..b4000ea5 --- /dev/null +++ b/krita/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/krita/ui/wdgnewimage.ui b/krita/ui/wdgnewimage.ui new file mode 100644 index 00000000..a85c1469 --- /dev/null +++ b/krita/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 + + + + + + + + + layout1 + + + + 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/krita/ui/wdgpalettechooser.ui b/krita/ui/wdgpalettechooser.ui new file mode 100644 index 00000000..f1840dd8 --- /dev/null +++ b/krita/ui/wdgpalettechooser.ui @@ -0,0 +1,105 @@ + +KisPaletteChooser + + + KisPaletteChooser + + + + 0 + 0 + 289 + 163 + + + + Choose Palette + + + true + + + + unnamed + + + + paletteList + + + + + layout2 + + + + 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/krita/ui/wdgperformancesettings.ui b/krita/ui/wdgperformancesettings.ui new file mode 100644 index 00000000..e5f1b9c8 --- /dev/null +++ b/krita/ui/wdgperformancesettings.ui @@ -0,0 +1,146 @@ + +WdgPerformanceSettings + + + WdgPerformanceSettings + + + + 0 + 0 + 495 + 220 + + + + + unnamed + + + + layout4 + + + + 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 Krita, 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 Krita, and is not guaranteed to be the actual number of tiles in memory. + + + + + spacer2 + + + Horizontal + + + Expanding + + + + 81 + 20 + + + + + + + + layout5 + + + + unnamed + + + + textLabel2 + + + Swappiness: + + + This configures how much Krita will use the swap file. If you move the slider all the way to the left, Krita will not use the swap file at all. If you move it all the way to the right, Krita will make maximum use of the swap file. + + + + + m_swappiness + + + + 600 + 32767 + + + + 6 + + + 3 + + + Horizontal + + + Below + + + This configures how much Krita 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/krita/ui/wdgpressuresettings.ui b/krita/ui/wdgpressuresettings.ui new file mode 100644 index 00000000..a081142c --- /dev/null +++ b/krita/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/krita/ui/wdgselectionoptions.ui b/krita/ui/wdgselectionoptions.ui new file mode 100644 index 00000000..13c9394d --- /dev/null +++ b/krita/ui/wdgselectionoptions.ui @@ -0,0 +1,64 @@ + +WdgSelectionOptions + + + WdgSelectionOptions + + + + 0 + 0 + 180 + 34 + + + + + unnamed + + + 0 + + + 0 + + + + layout1 + + + + unnamed + + + 6 + + + + lblAction + + + Action: + + + + + + Add + + + + + Subtract + + + + cmbAction + + + + + + + + diff --git a/krita/ui/wdgshapeoptions.ui b/krita/ui/wdgshapeoptions.ui new file mode 100644 index 00000000..9c18771e --- /dev/null +++ b/krita/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/krita/ui/wdgtabletdevicesettings.ui b/krita/ui/wdgtabletdevicesettings.ui new file mode 100644 index 00000000..07f90d30 --- /dev/null +++ b/krita/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 + + + + layout4 + + + + unnamed + + + + textLabel1_2 + + + X: + + + + + cbX + + + + + + + layout4_4 + + + + unnamed + + + + textLabel1_2_4 + + + Y: + + + + + cbY + + + + + + + layout4_2 + + + + unnamed + + + + textLabel1_2_2 + + + Pressure: + + + + + cbPressure + + + + + + + layout4_3 + + + + unnamed + + + + textLabel1_2_3 + + + X tilt: + + + + + cbXTilt + + + + + + + layout4_6 + + + + unnamed + + + + textLabel1_2_6 + + + Y tilt: + + + + + cbYTilt + + + + + + + layout4_5 + + + + unnamed + + + + textLabel1_2_5 + + + Wheel: + + + + + cbWheel + + + + + + + + + + diff --git a/krita/ui/wdgtabletsettings.ui b/krita/ui/wdgtabletsettings.ui new file mode 100644 index 00000000..775f1e9b --- /dev/null +++ b/krita/ui/wdgtabletsettings.ui @@ -0,0 +1,104 @@ + +WdgTabletSettings + + + WdgTabletSettings + + + + 0 + 0 + 510 + 268 + + + + Tablet + + + + unnamed + + + + grpTabletDevices + + + Tablet Devices + + + + unnamed + + + + layout4 + + + + unnamed + + + + textLabel1 + + + Device: + + + + + cbTabletDevice + + + + + + + layout5 + + + + unnamed + + + + chkEnableTabletDevice + + + Enable + + + + + btnConfigureTabletDevice + + + Configure... + + + + + + + + + spacer1 + + + Vertical + + + Expanding + + + + 21 + 90 + + + + + + + diff --git a/krita/ui/wdgtextbrush.ui b/krita/ui/wdgtextbrush.ui new file mode 100644 index 00000000..4126dc76 --- /dev/null +++ b/krita/ui/wdgtextbrush.ui @@ -0,0 +1,158 @@ + +KisWdgTextBrush + + + KisWdgTextBrush + + + + 0 + 0 + 317 + 89 + + + + Text + + + + unnamed + + + + layout3 + + + + unnamed + + + + layout9 + + + + unnamed + + + + labelText + + + Text: + + + + + lineEdit + + + + 120 + 0 + + + + + + + + The Quick Brown Fox Jumps Over The Lazy Dog + + + + + + + layout10 + + + + 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 + + -- cgit v1.2.1