diff --git a/krita/image/CMakeLists.txt b/krita/image/CMakeLists.txt index 3116a01059..fa61e9b3dc 100644 --- a/krita/image/CMakeLists.txt +++ b/krita/image/CMakeLists.txt @@ -1,368 +1,367 @@ add_subdirectory( tests ) ########### next target ############### kde_enable_exceptions() # Chose a tiles backend # 1 - image/tiles # 3 - image/tiles3 set(USE_TILESYSTEM 3) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config-tiles.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/../config-tiles.h) ### WRONG PLACE??? if(USE_TILESYSTEM EQUAL 3) set(libkritatile_SRCS ${CMAKE_SOURCE_DIR}/krita/image/tiles3/kis_tile.cc ${CMAKE_SOURCE_DIR}/krita/image/tiles3/kis_tile_data.cc ${CMAKE_SOURCE_DIR}/krita/image/tiles3/kis_tile_data_store.cc ${CMAKE_SOURCE_DIR}/krita/image/tiles3/kis_tile_data_pooler.cc ${CMAKE_SOURCE_DIR}/krita/image/tiles3/kis_tiled_data_manager.cc ${CMAKE_SOURCE_DIR}/krita/image/tiles3/kis_memento_manager.cc ${CMAKE_SOURCE_DIR}/krita/image/tiles3/kis_hline_iterator.cpp ${CMAKE_SOURCE_DIR}/krita/image/tiles3/kis_vline_iterator.cpp ${CMAKE_SOURCE_DIR}/krita/image/tiles3/kis_random_accessor.cc ${CMAKE_SOURCE_DIR}/krita/image/tiles3/swap/kis_abstract_compression.cpp ${CMAKE_SOURCE_DIR}/krita/image/tiles3/swap/kis_lzf_compression.cpp ${CMAKE_SOURCE_DIR}/krita/image/tiles3/swap/kis_abstract_tile_compressor.cpp ${CMAKE_SOURCE_DIR}/krita/image/tiles3/swap/kis_legacy_tile_compressor.cpp ${CMAKE_SOURCE_DIR}/krita/image/tiles3/swap/kis_tile_compressor_2.cpp ${CMAKE_SOURCE_DIR}/krita/image/tiles3/swap/kis_chunk_allocator.cpp ${CMAKE_SOURCE_DIR}/krita/image/tiles3/swap/kis_memory_window.cpp ${CMAKE_SOURCE_DIR}/krita/image/tiles3/swap/kis_swapped_data_store.cpp ${CMAKE_SOURCE_DIR}/krita/image/tiles3/swap/kis_tile_data_swapper.cpp ) add_subdirectory( tiles3 ) endif() option(HAVE_MEMORY_LEAK_TRACKER "Enable memory leak tracker (always disabled in release build)" OFF) option(HAVE_BACKTRACE_SUPPORT "Enable recording of backtrace in memory leak tracker" OFF) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config-memory-leak-tracker.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-memory-leak-tracker.h) ### WRONG PLACE??? include_directories( ${CMAKE_SOURCE_DIR}/krita/image/metadata 3rdparty ) if(FFTW3_FOUND) include_directories(${FFTW3_INCLUDE_DIR}) endif() if(HAVE_VC) include_directories(${Vc_INCLUDE_DIR} ${Qt5Core_INCLUDE_DIRS} ${Qt5Gui_INCLUDE_DIRS}) ko_compile_for_all_implementations(__per_arch_circle_mask_generator_objs kis_brush_mask_applicator_factories.cpp) else() set(__per_arch_circle_mask_generator_objs kis_brush_mask_applicator_factories.cpp) endif() set(kritaimage_LIB_SRCS ${libkritatile_SRCS} kis_distance_information.cpp kis_painter.cc kis_progress_updater.cpp brushengine/kis_paint_information.cc brushengine/kis_random_source.cpp brushengine/kis_stroke_random_source.cpp brushengine/kis_paintop.cc brushengine/kis_paintop_factory.cpp brushengine/kis_paintop_preset.cpp brushengine/kis_paintop_registry.cc brushengine/kis_paintop_settings.cpp brushengine/kis_locked_properties.cc brushengine/kis_locked_properties_proxy.cpp brushengine/kis_locked_properties_server.cpp brushengine/kis_paintop_config_widget.cpp commands/kis_deselect_global_selection_command.cpp commands/kis_image_change_layers_command.cpp commands/kis_image_command.cpp commands/kis_image_set_projection_color_space_command.cpp commands/kis_image_layer_add_command.cpp commands/kis_image_layer_move_command.cpp commands/kis_image_layer_remove_command.cpp commands/kis_image_layer_remove_command_impl.cpp commands/kis_image_node_lower_command.cpp commands/kis_image_node_raise_command.cpp commands/kis_image_node_to_bottom_command.cpp commands/kis_image_node_to_top_command.cpp commands/kis_image_lock_command.cpp commands/kis_layer_command.cpp commands/kis_layer_props_command.cpp commands/kis_node_command.cpp commands/kis_node_compositeop_command.cpp commands/kis_node_opacity_command.cpp commands/kis_node_property_list_command.cpp commands/kis_reselect_global_selection_command.cpp commands/kis_set_global_selection_command.cpp commands_new/kis_saved_commands.cpp commands_new/kis_processing_command.cpp commands_new/kis_image_resize_command.cpp commands_new/kis_image_set_resolution_command.cpp commands_new/kis_node_move_command2.cpp commands_new/kis_set_layer_style_command.cpp commands_new/kis_selection_move_command2.cpp commands_new/kis_update_command.cpp commands_new/kis_switch_current_time_command.cpp commands_new/kis_activate_selection_mask_command.cpp processing/kis_do_nothing_processing_visitor.cpp processing/kis_simple_processing_visitor.cpp processing/kis_crop_processing_visitor.cpp processing/kis_crop_selections_processing_visitor.cpp processing/kis_transform_processing_visitor.cpp processing/kis_mirror_processing_visitor.cpp filter/kis_filter.cc filter/kis_filter_configuration.cc filter/kis_color_transformation_configuration.cc filter/kis_filter_registry.cc filter/kis_color_transformation_filter.cc generator/kis_generator.cpp generator/kis_generator_layer.cpp generator/kis_generator_registry.cpp floodfill/kis_fill_interval_map.cpp floodfill/kis_scanline_fill.cpp kis_adjustment_layer.cc kis_selection_based_layer.cpp kis_node_filter_interface.cpp kis_base_accessor.cpp kis_base_node.cpp kis_base_processor.cpp - kis_basic_math_toolbox.cpp kis_bookmarked_configuration_manager.cc kis_clone_info.cpp kis_clone_layer.cpp kis_colorspace_convert_visitor.cpp kis_config_widget.cpp kis_convolution_kernel.cc kis_convolution_painter.cc kis_gaussian_kernel.cpp kis_cubic_curve.cpp kis_default_bounds.cpp kis_default_bounds_base.cpp kis_effect_mask.cc kis_fast_math.cpp kis_fill_painter.cc kis_filter_mask.cpp kis_filter_strategy.cc kis_transform_mask.cpp kis_transform_mask_params_interface.cpp kis_recalculate_transform_mask_job.cpp kis_recalculate_generator_layer_job.cpp kis_transform_mask_params_factory_registry.cpp kis_safe_transform.cpp kis_gradient_painter.cc kis_gradient_shape_strategy.cpp kis_cached_gradient_shape_strategy.cpp kis_polygonal_gradient_shape_strategy.cpp kis_iterator_ng.cpp kis_async_merger.cpp kis_merge_walker.cc kis_updater_context.cpp kis_update_job_item.cpp kis_stroke_strategy_undo_command_based.cpp kis_simple_stroke_strategy.cpp kis_stroke_job_strategy.cpp kis_stroke_strategy.cpp kis_stroke.cpp kis_strokes_queue.cpp kis_simple_update_queue.cpp kis_update_scheduler.cpp kis_queues_progress_updater.cpp kis_composite_progress_proxy.cpp kis_sync_lod_cache_stroke_strategy.cpp kis_lod_capable_layer_offset.cpp kis_update_time_monitor.cpp kis_group_layer.cc kis_count_visitor.cpp kis_histogram.cc kis_image_interfaces.cpp kis_image_animation_interface.cpp kis_time_range.cpp kis_node_graph_listener.cpp kis_image.cc kis_image_signal_router.cpp kis_image_config.cpp kis_projection_updates_filter.cpp kis_suspend_projection_updates_stroke_strategy.cpp kis_regenerate_frame_stroke_strategy.cpp kis_crop_saved_extra_data.cpp kis_signal_compressor.cpp kis_signal_compressor_with_param.cpp kis_thread_safe_signal_compressor.cpp kis_acyclic_signal_connector.cpp kis_layer.cc kis_indirect_painting_support.cpp kis_abstract_projection_plane.cpp kis_layer_projection_plane.cpp kis_mask_projection_plane.cpp kis_projection_leaf.cpp kis_mask.cc kis_base_mask_generator.cpp kis_rect_mask_generator.cpp kis_circle_mask_generator.cpp kis_gauss_circle_mask_generator.cpp kis_gauss_rect_mask_generator.cpp ${__per_arch_circle_mask_generator_objs} kis_curve_circle_mask_generator.cpp kis_curve_rect_mask_generator.cpp kis_math_toolbox.cpp kis_memory_leak_tracker.cpp kis_memory_statistics_server.cpp kis_name_server.cpp kis_node.cpp kis_node_facade.cpp kis_node_progress_proxy.cpp kis_busy_progress_indicator.cpp kis_node_visitor.cpp kis_paint_device.cc kis_paint_device_debug_utils.cpp kis_fixed_paint_device.cpp kis_paint_layer.cc kis_perspective_grid.cpp kis_perspective_math.cpp kis_pixel_selection.cpp kis_processing_information.cpp kis_properties_configuration.cc kis_random_accessor_ng.cpp kis_random_generator.cc kis_random_sub_accessor.cpp kis_wrapped_random_accessor.cpp kis_selection.cc kis_selection_mask.cpp kis_update_outline_job.cpp kis_update_selection_job.cpp kis_serializable_configuration.cc kis_shared.cc kis_transaction_data.cpp kis_transform_worker.cc kis_perspectivetransform_worker.cpp bsplines/kis_bspline_1d.cpp bsplines/kis_bspline_2d.cpp bsplines/kis_nu_bspline_2d.cpp kis_warptransform_worker.cc kis_cage_transform_worker.cpp kis_liquify_transform_worker.cpp kis_green_coordinates_math.cpp kis_algebra_2d.cpp kis_dom_utils.cpp kis_transparency_mask.cc kis_undo_store.cpp kis_undo_stores.cpp kis_undo_adapter.cpp kis_surrogate_undo_adapter.cpp kis_legacy_undo_adapter.cpp kis_post_execution_undo_adapter.cpp kis_processing_visitor.cpp kis_processing_applicator.cpp krita_utils.cpp kis_outline_generator.cpp kis_layer_composition.cpp kis_selection_filters.cpp metadata/kis_meta_data_entry.cc metadata/kis_meta_data_filter.cc metadata/kis_meta_data_filter_p.cc metadata/kis_meta_data_filter_registry.cc metadata/kis_meta_data_filter_registry_model.cc metadata/kis_meta_data_io_backend.cc metadata/kis_meta_data_merge_strategy.cc metadata/kis_meta_data_merge_strategy_p.cc metadata/kis_meta_data_merge_strategy_registry.cc metadata/kis_meta_data_parser.cc metadata/kis_meta_data_schema.cc metadata/kis_meta_data_schema_registry.cc metadata/kis_meta_data_store.cc metadata/kis_meta_data_type_info.cc metadata/kis_meta_data_validator.cc metadata/kis_meta_data_value.cc recorder/kis_action_recorder.cc recorder/kis_macro.cc recorder/kis_macro_player.cc recorder/kis_node_query_path.cc recorder/kis_play_info.cc recorder/kis_recorded_action.cc recorder/kis_recorded_action_factory_registry.cc recorder/kis_recorded_action_load_context.cpp recorder/kis_recorded_action_save_context.cpp recorder/kis_recorded_filter_action.cpp recorder/kis_recorded_fill_paint_action.cpp recorder/kis_recorded_node_action.cc recorder/kis_recorded_paint_action.cpp recorder/kis_recorded_path_paint_action.cpp recorder/kis_recorded_shape_paint_action.cpp kis_keyframe.cpp kis_keyframe_channel.cpp kis_scalar_keyframe_channel.cpp kis_raster_keyframe_channel.cpp kis_onion_skin_compositor.cpp kis_idle_watcher.cpp kis_psd_layer_style.cpp kis_layer_properties_icons.cpp layerstyles/kis_multiple_projection.cpp layerstyles/kis_layer_style_filter.cpp layerstyles/kis_layer_style_filter_environment.cpp layerstyles/kis_layer_style_filter_projection_plane.cpp layerstyles/kis_layer_style_projection_plane.cpp layerstyles/kis_ls_drop_shadow_filter.cpp layerstyles/kis_ls_satin_filter.cpp layerstyles/kis_ls_stroke_filter.cpp layerstyles/kis_ls_bevel_emboss_filter.cpp layerstyles/kis_ls_overlay_filter.cpp layerstyles/kis_ls_utils.cpp layerstyles/gimp_bump_map.cpp ) set(einspline_SRCS 3rdparty/einspline/bspline_create.cpp 3rdparty/einspline/bspline_data.cpp 3rdparty/einspline/multi_bspline_create.cpp 3rdparty/einspline/nubasis.cpp 3rdparty/einspline/nubspline_create.cpp 3rdparty/einspline/nugrid.cpp ) add_library(kritaimage SHARED ${kritaimage_LIB_SRCS} ${einspline_SRCS}) generate_export_header(kritaimage BASE_NAME kritaimage) target_link_libraries(kritaimage kritaversion kritawidgets kritaglobal kritapsd kritaodf kritapigment kritaundo2 kritawidgetutils Qt5::Concurrent) target_link_libraries(kritaimage LINK_INTERFACE_LIBRARIES kritaversion kritaglobal kritapsd kritaodf kritapigment kritaundo2 kritawidgetutils Qt5::Concurrent) target_link_libraries(kritaimage ${Boost_SYSTEM_LIBRARY}) message("DEBUG_BOOST_LIBRARIES = " ${Boost_LIBRARIES}) message("DEBUG_BOOST_SYSTEM_FOUND = " ${Boost_SYSTEM_FOUND}) message("DEBUG_BOOST_SYSTEM_LIBRARY = " ${Boost_SYSTEM_LIBRARY}) if(OPENEXR_FOUND) target_link_libraries(kritaimage ${OPENEXR_LIBRARIES}) endif() if(FFTW3_FOUND) target_link_libraries(kritaimage ${FFTW3_LIBRARIES}) endif() if(HAVE_VC) target_link_libraries(kritaimage ${Vc_LIBRARIES}) endif() if (NOT GSL_FOUND) message (WARNING "KRITA WARNING! No GNU Scientific Library was found! Krita's Shaped Gradients might be non-normalized! Please install GSL library.") else () target_link_libraries(kritaimage ${GSL_LIBRARIES} ${GSL_CBLAS_LIBRARIES}) endif () set_target_properties(kritaimage PROPERTIES VERSION ${GENERIC_CALLIGRA_LIB_VERSION} SOVERSION ${GENERIC_CALLIGRA_LIB_SOVERSION} ) install(TARGETS kritaimage ${INSTALL_TARGETS_DEFAULT_ARGS}) ########### install schemas ############# install( FILES metadata/schemas/dc.schema metadata/schemas/exif.schema metadata/schemas/tiff.schema metadata/schemas/mkn.schema metadata/schemas/xmp.schema metadata/schemas/xmpmm.schema metadata/schemas/xmprights.schema DESTINATION ${DATA_INSTALL_DIR}/krita/metadata/schemas) diff --git a/krita/image/kis_basic_math_toolbox.cpp b/krita/image/kis_basic_math_toolbox.cpp deleted file mode 100644 index 7c78ce41c5..0000000000 --- a/krita/image/kis_basic_math_toolbox.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/* - * 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" -#include - -KisBasicMathToolbox::KisBasicMathToolbox() - : KisMathToolbox(KoID("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/image/kis_basic_math_toolbox.h b/krita/image/kis_basic_math_toolbox.h deleted file mode 100644 index 98aaf25aef..0000000000 --- a/krita/image/kis_basic_math_toolbox.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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" -#include "kritaimage_export.h" -/** - * This class implement KisMathToolbox for most colorspaces, only colorspaces with "angular" - * channels need to reimplement the functions - */ -class KRITAIMAGE_EXPORT 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/image/kis_convolution_worker_fft.h b/krita/image/kis_convolution_worker_fft.h index a05beedae0..009f1dee56 100644 --- a/krita/image/kis_convolution_worker_fft.h +++ b/krita/image/kis_convolution_worker_fft.h @@ -1,510 +1,510 @@ /* * Copyright (c) 2010 Edward Apap * Copyright (c) 2011 José Luis Vergara Toloza * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along 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_WORKER_FFT_H #define KIS_CONVOLUTION_WORKER_FFT_H #include #include #include "kis_convolution_worker.h" #include "kis_math_toolbox.h" #include #include #include #include #include #include template class KisConvolutionWorkerFFT; class KisConvolutionWorkerFFTLock { private: static QMutex fftwMutex; template friend class KisConvolutionWorkerFFT; }; QMutex KisConvolutionWorkerFFTLock::fftwMutex; template class KisConvolutionWorkerFFT : public KisConvolutionWorker<_IteratorFactory_> { public: KisConvolutionWorkerFFT(KisPainter *painter, KoUpdater *progress) : KisConvolutionWorker<_IteratorFactory_>(painter, progress), m_currentProgress(0), m_kernelFFT(0) { } ~KisConvolutionWorkerFFT() { } virtual void execute(const KisConvolutionKernelSP kernel, const KisPaintDeviceSP src, QPoint srcPos, QPoint dstPos, QSize areaSize, const QRect& dataRect) { // Make the area we cover as small as possible if (this->m_painter->selection()) { QRect r = this->m_painter->selection()->selectedRect().intersect(QRect(srcPos, areaSize)); dstPos += r.topLeft() - srcPos; srcPos = r.topLeft(); areaSize = r.size(); } if (areaSize.width() == 0 || areaSize.height() == 0) return; addToProgress(0); if (isInterrupted()) return; const quint32 halfKernelWidth = (kernel->width() - 1) / 2; const quint32 halfKernelHeight = (kernel->height() - 1) / 2; m_fftWidth = areaSize.width() + 4 * halfKernelWidth; m_fftHeight = areaSize.height() + 2 * halfKernelHeight; /** * FIXME: check whether this "optimization" is needed to * be uncommented. My tests showed about 30% better performance * when the line is commented out (DK). */ //optimumDimensions(m_fftWidth, m_fftHeight); m_fftLength = m_fftHeight * (m_fftWidth / 2 + 1); m_extraMem = (m_fftWidth % 2) ? 1 : 2; // create and fill kernel m_kernelFFT = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * m_fftLength); memset(m_kernelFFT, 0, sizeof(fftw_complex) * m_fftLength); fftFillKernelMatrix(kernel, m_kernelFFT); // find out which channels need convolving QList convChannelList = this->convolvableChannelList(src); m_channelFFT.resize(convChannelList.count()); for (auto i = m_channelFFT.begin(); i != m_channelFFT.end(); ++i) { *i = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * m_fftLength); } const double kernelFactor = kernel->factor() ? kernel->factor() : 1; const double fftScale = 1.0 / (m_fftHeight * m_fftWidth) / kernelFactor; FFTInfo info (fftScale, convChannelList, kernel, this->m_painter->device()->colorSpace()); int cacheRowStride = m_fftWidth + m_extraMem; fillCacheFromDevice(src, QRect(srcPos.x() - halfKernelWidth, srcPos.y() - halfKernelHeight, m_fftWidth, m_fftHeight), cacheRowStride, info, dataRect); addToProgress(10); if (isInterrupted()) return; // calculate number off fft operations required for progress reporting const float progressPerFFT = (100 - 30) / (double)(convChannelList.count() * 2 + 1); // perform FFT fftw_plan fftwPlanForward, fftwPlanBackward; KisConvolutionWorkerFFTLock::fftwMutex.lock(); fftwPlanForward = fftw_plan_dft_r2c_2d(m_fftHeight, m_fftWidth, (double*)m_kernelFFT, m_kernelFFT, FFTW_ESTIMATE); fftwPlanBackward = fftw_plan_dft_c2r_2d(m_fftHeight, m_fftWidth, m_kernelFFT, (double*)m_kernelFFT, FFTW_ESTIMATE); KisConvolutionWorkerFFTLock::fftwMutex.unlock(); fftw_execute(fftwPlanForward); addToProgress(progressPerFFT); if (isInterrupted()) return; for (auto k = m_channelFFT.begin(); k != m_channelFFT.end(); ++k) { fftw_execute_dft_r2c(fftwPlanForward, (double*)(*k), *k); addToProgress(progressPerFFT); if (isInterrupted()) return; fftMultiply(*k, m_kernelFFT); fftw_execute_dft_c2r(fftwPlanBackward, *k, (double*)*k); addToProgress(progressPerFFT); if (isInterrupted()) return; } KisConvolutionWorkerFFTLock::fftwMutex.lock(); fftw_destroy_plan(fftwPlanForward); fftw_destroy_plan(fftwPlanBackward); KisConvolutionWorkerFFTLock::fftwMutex.unlock(); writeResultToDevice(QRect(dstPos.x(), dstPos.y(), areaSize.width(), areaSize.height()), cacheRowStride, halfKernelWidth, halfKernelHeight, info, dataRect); addToProgress(20); cleanUp(); } struct FFTInfo { FFTInfo(qreal _fftScale, QList _convChannelList, const KisConvolutionKernelSP kernel, const KoColorSpace *colorSpace) : fftScale(_fftScale), convChannelList(_convChannelList), alphaCachePos(-1), alphaRealPos(-1) { - KisMathToolbox* mathToolbox = KisMathToolboxRegistry::instance()->value(colorSpace->mathToolboxId().id()); + KisMathToolbox mathToolbox; for (int i = 0; i < convChannelList.count(); ++i) { - minClamp.append(mathToolbox->minChannelValue(convChannelList[i])); - maxClamp.append(mathToolbox->maxChannelValue(convChannelList[i])); + minClamp.append(mathToolbox.minChannelValue(convChannelList[i])); + maxClamp.append(mathToolbox.maxChannelValue(convChannelList[i])); absoluteOffset.append((maxClamp[i] - minClamp[i]) * kernel->offset()); if (convChannelList[i]->channelType() == KoChannelInfo::ALPHA) { alphaCachePos = i; alphaRealPos = convChannelList[i]->pos(); } } toDoubleFuncPtr.resize(convChannelList.count()); fromDoubleFuncPtr.resize(convChannelList.count()); - bool result = mathToolbox->getToDoubleChannelPtr(convChannelList, toDoubleFuncPtr); - result &= mathToolbox->getFromDoubleChannelPtr(convChannelList, fromDoubleFuncPtr); + bool result = mathToolbox.getToDoubleChannelPtr(convChannelList, toDoubleFuncPtr); + result &= mathToolbox.getFromDoubleChannelPtr(convChannelList, fromDoubleFuncPtr); KIS_ASSERT(result); } inline int numChannels() const { return convChannelList.size(); } QVector minClamp; QVector maxClamp; QVector absoluteOffset; qreal fftScale; QList convChannelList; QVector toDoubleFuncPtr; QVector fromDoubleFuncPtr; int alphaCachePos; int alphaRealPos; }; void fillCacheFromDevice(KisPaintDeviceSP src, const QRect &rect, const int cacheRowStride, const FFTInfo &info, const QRect &dataRect) { typename _IteratorFactory_::HLineConstIterator hitSrc = _IteratorFactory_::createHLineConstIterator(src, rect.x(), rect.y(), rect.width(), dataRect); QVector channelPtr(info.numChannels()); for (int k = 0; k < channelPtr.size(); ++k) { channelPtr[k] = (double*)m_channelFFT[k]; } for (int y = 0; y < rect.height(); ++y) { QVector cacheRowStart(channelPtr); for (int x = 0; x < rect.width(); ++x) { const quint8 *data = hitSrc->oldRawData(); // no alpha is a rare case, so just multiply by 1.0 in that case double alphaValue = info.alphaRealPos >= 0 ? info.toDoubleFuncPtr[info.alphaCachePos](data, info.alphaRealPos) : 1.0; for (int k = 0; k < channelPtr.size(); ++k) { if (k != info.alphaCachePos) { const quint32 channelPos = info.convChannelList[k]->pos(); *channelPtr[k] = info.toDoubleFuncPtr[k](data, channelPos) * alphaValue; } else { *channelPtr[k] = alphaValue; } channelPtr[k]++; } hitSrc->nextPixel(); } for (int k = 0; k < channelPtr.size(); ++k) { channelPtr[k] = cacheRowStart[k] + cacheRowStride; } hitSrc->nextRow(); } } inline void limitValue(qreal *value, qreal lowBound, qreal highBound) { if (*value > highBound) { *value = highBound; } else if (*value < lowBound){ *value = lowBound; } } template inline qreal writeOneChannelFromCache(quint8* dstPtr, const quint32 channel, const int channelPos, const FFTInfo &info, const QVector &channelPtr, const qreal additionalMultiplier = 0.0) { qreal channelPixelValue; if (additionalMultiplierActive) { channelPixelValue = (*(channelPtr[channel]) * info.fftScale + info.absoluteOffset[channel]) * additionalMultiplier; } else { channelPixelValue = *(channelPtr[channel]) * info.fftScale + info.absoluteOffset[channel]; } limitValue(&channelPixelValue, info.minClamp[channel], info.maxClamp[channel]); info.fromDoubleFuncPtr[channel](dstPtr, channelPos, channelPixelValue); return channelPixelValue; } void writeResultToDevice(const QRect &rect, const int cacheRowStride, const int halfKernelWidth, const int halfKernelHeight, const FFTInfo &info, const QRect &dataRect) { typename _IteratorFactory_::HLineIterator hitDst = _IteratorFactory_::createHLineIterator(this->m_painter->device(), rect.x(), rect.y(), rect.width(), dataRect); int initialOffset = cacheRowStride * halfKernelHeight + halfKernelWidth; QVector channelPtr(info.numChannels()); for (int k = 0; k < channelPtr.size(); ++k) { channelPtr[k] = (double*)m_channelFFT[k] + initialOffset; } for (int y = 0; y < rect.height(); ++y) { QVector cacheRowStart(channelPtr); for (int x = 0; x < rect.width(); ++x) { quint8 *dstPtr = hitDst->rawData(); if (info.alphaCachePos >= 0) { qreal alphaValue = writeOneChannelFromCache(dstPtr, info.alphaCachePos, info.convChannelList[info.alphaCachePos]->pos(), info, channelPtr); qreal alphaValueInv = 1.0 / alphaValue; for (int k = 0; k < channelPtr.size(); ++k) { if (k != info.alphaCachePos) { writeOneChannelFromCache(dstPtr, k, info.convChannelList[k]->pos(), info, channelPtr, alphaValueInv); } ++channelPtr[k]; } } else { for (int k = 0; k < channelPtr.size(); ++k) { writeOneChannelFromCache(dstPtr, k, info.convChannelList[k]->pos(), info, channelPtr); ++channelPtr[k]; } } hitDst->nextPixel(); } for (int k = 0; k < channelPtr.size(); ++k) { channelPtr[k] = cacheRowStart[k] + cacheRowStride; } hitDst->nextRow(); } } private: void fftFillKernelMatrix(const KisConvolutionKernelSP kernel, fftw_complex *m_kernelFFT) { // find central item QPoint offset((kernel->width() - 1) / 2, (kernel->height() - 1) / 2); qint32 xShift = m_fftWidth - offset.x(); qint32 yShift = m_fftHeight - offset.y(); quint32 absXpos, absYpos; for (quint32 y = 0; y < kernel->height(); y++) { absYpos = y + yShift; if (absYpos >= m_fftHeight) absYpos -= m_fftHeight; for (quint32 x = 0; x < kernel->width(); x++) { absXpos = x + xShift; if (absXpos >= m_fftWidth) absXpos -= m_fftWidth; ((double*)m_kernelFFT)[(m_fftWidth + m_extraMem) * absYpos + absXpos] = kernel->data()->coeff(y, x); } } } void fftMultiply(fftw_complex* channel, fftw_complex* kernel) { // perform complex multiplication fftw_complex *channelPtr = channel; fftw_complex *kernelPtr = kernel; fftw_complex tmp; for (quint32 pixelPos = 0; pixelPos < m_fftLength; ++pixelPos) { tmp[0] = ((*channelPtr)[0] * (*kernelPtr)[0]) - ((*channelPtr)[1] * (*kernelPtr)[1]); tmp[1] = ((*channelPtr)[0] * (*kernelPtr)[1]) + ((*channelPtr)[1] * (*kernelPtr)[0]); (*channelPtr)[0] = tmp[0]; (*channelPtr)[1] = tmp[1]; ++channelPtr; ++kernelPtr; } } void optimumDimensions(quint32& w, quint32& h) { // FFTW is most efficient when array size is a factor of 2, 3, 5 or 7 quint32 optW = w, optH = h; while ((optW % 2 != 0) || (optW % 3 != 0) || (optW % 5 != 0) || (optW % 7 != 0)) ++optW; while ((optH % 2 != 0) || (optH % 3 != 0) || (optH % 5 != 0) || (optH % 7 != 0)) ++optH; quint32 optAreaW = optW * h; quint32 optAreaH = optH * w; if (optAreaW < optAreaH) { w = optW; } else { h = optH; } } void fftLogMatrix(double* channel, QString f) { KisConvolutionWorkerFFTLock::fftwMutex.lock(); QString filename(QDir::homePath() + "/log_" + f + ".txt"); dbgKrita << "Log File Name: " << filename; QFile file (filename); if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) { dbgKrita << "Failed"; KisConvolutionWorkerFFTLock::fftwMutex.unlock(); return; } QTextStream in(&file); for (quint32 y = 0; y < m_fftHeight; y++) { for (quint32 x = 0; x < m_fftWidth; x++) { QString num = QString::number(channel[y * m_fftWidth + x]); while (num.length() < 15) num += " "; in << num << " "; } in << "\n"; } KisConvolutionWorkerFFTLock::fftwMutex.unlock(); } void addToProgress(float amount) { m_currentProgress += amount; if (this->m_progress) { this->m_progress->setProgress((int)m_currentProgress); } } bool isInterrupted() { if (this->m_progress && this->m_progress->interrupted()) { cleanUp(); return true; } return false; } void cleanUp() { // free kernel fft data if (m_kernelFFT) { fftw_free(m_kernelFFT); } Q_FOREACH (fftw_complex *channel, m_channelFFT) { fftw_free(channel); } m_channelFFT.clear(); } private: quint32 m_fftWidth, m_fftHeight, m_fftLength, m_extraMem; float m_currentProgress; fftw_complex* m_kernelFFT; QVector m_channelFFT; }; #endif diff --git a/krita/image/kis_convolution_worker_spatial.h b/krita/image/kis_convolution_worker_spatial.h index fb340173e8..55287a9fb4 100644 --- a/krita/image/kis_convolution_worker_spatial.h +++ b/krita/image/kis_convolution_worker_spatial.h @@ -1,380 +1,380 @@ /* * Copyright (c) 2005, 2008, 2010 Cyrille Berger * Copyright (c) 2009, 2010 Edward Apap * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along 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_WORKER_SPATIAL_H #define KIS_CONVOLUTION_WORKER_SPATIAL_H #include "kis_convolution_worker.h" #include "kis_math_toolbox.h" template class KisConvolutionWorkerSpatial : public KisConvolutionWorker<_IteratorFactory_> { public: KisConvolutionWorkerSpatial(KisPainter *painter, KoUpdater *progress) : KisConvolutionWorker<_IteratorFactory_>(painter, progress) , m_alphaCachePos(-1) , m_alphaRealPos(-1) , m_pixelPtrCache(0) , m_pixelPtrCacheCopy(0) , m_minClamp(0) , m_maxClamp(0) , m_absoluteOffset(0) { } ~KisConvolutionWorkerSpatial() { } inline void loadPixelToCache(qreal **cache, const quint8 *data, int index) { // no alpha is rare case, so just multiply by 1.0 in that case qreal alphaValue = m_alphaRealPos >= 0 ? m_toDoubleFuncPtr[m_alphaCachePos](data, m_alphaRealPos) : 1.0; for (quint32 k = 0; k < m_convolveChannelsNo; ++k) { if (k != (quint32)m_alphaCachePos) { const quint32 channelPos = m_convChannelList[k]->pos(); cache[index][k] = m_toDoubleFuncPtr[k](data, channelPos) * alphaValue; } else { cache[index][k] = alphaValue; } } } virtual void execute(const KisConvolutionKernelSP kernel, const KisPaintDeviceSP src, QPoint srcPos, QPoint dstPos, QSize areaSize, const QRect& dataRect) { // store some kernel characteristics m_kw = kernel->width(); m_kh = kernel->height(); m_khalfWidth = (m_kw - 1) / 2; m_khalfHeight = (m_kh - 1) / 2; m_cacheSize = m_kw * m_kh; m_pixelSize = src->colorSpace()->pixelSize(); quint32 channelCount = src->colorSpace()->channelCount(); m_kernelData = new qreal[m_cacheSize]; qreal *kernelDataPtr = m_kernelData; // fill in data for (quint32 r = 0; r < kernel->height(); r++) { for (quint32 c = 0; c < kernel->width(); c++) { *kernelDataPtr = (*(kernel->data()))(r, c); kernelDataPtr++; } } // Make the area we cover as small as possible if (this->m_painter->selection()) { QRect r = this->m_painter->selection()->selectedRect().intersect(QRect(srcPos, areaSize)); dstPos += r.topLeft() - srcPos; srcPos = r.topLeft(); areaSize = r.size(); } if (areaSize.width() == 0 || areaSize.height() == 0) return; // Don't convolve with an even sized kernel Q_ASSERT((m_kw & 0x01) == 1 || (m_kh & 0x01) == 1 || kernel->factor() != 0); // find out which channels need be convolved m_convChannelList = this->convolvableChannelList(src); m_convolveChannelsNo = m_convChannelList.count(); for (int i = 0; i < m_convChannelList.size(); i++) { if (m_convChannelList[i]->channelType() == KoChannelInfo::ALPHA) { m_alphaCachePos = i; m_alphaRealPos = m_convChannelList[i]->pos(); } } bool hasProgressUpdater = this->m_progress; if (hasProgressUpdater) this->m_progress->setProgress(0); // Iterate over all pixels in our rect, create a cache of pixels around the current pixel and convolve them. m_pixelPtrCache = new qreal*[m_cacheSize]; m_pixelPtrCacheCopy = new qreal*[m_cacheSize]; for (quint32 c = 0; c < m_cacheSize; ++c) { m_pixelPtrCache[c] = new qreal[channelCount]; m_pixelPtrCacheCopy[c] = new qreal[channelCount]; } // decide caching strategy enum TraversingDirection { Horizontal, Vertical }; TraversingDirection traversingDirection = Vertical; if (m_kw > m_kh) { traversingDirection = Horizontal; } - KisMathToolbox* mathToolbox = KisMathToolboxRegistry::instance()->value(src->colorSpace()->mathToolboxId().id()); + KisMathToolbox mathToolbox; m_toDoubleFuncPtr = QVector(m_convolveChannelsNo); - if (!mathToolbox->getToDoubleChannelPtr(m_convChannelList, m_toDoubleFuncPtr)) + if (!mathToolbox.getToDoubleChannelPtr(m_convChannelList, m_toDoubleFuncPtr)) return; m_fromDoubleFuncPtr = QVector(m_convolveChannelsNo); - if (!mathToolbox->getFromDoubleChannelPtr(m_convChannelList, m_fromDoubleFuncPtr)) + if (!mathToolbox.getFromDoubleChannelPtr(m_convChannelList, m_fromDoubleFuncPtr)) return; m_kernelFactor = kernel->factor() ? 1.0 / kernel->factor() : 1; m_maxClamp = new qreal[m_convChannelList.count()]; m_minClamp = new qreal[m_convChannelList.count()]; m_absoluteOffset = new qreal[m_convChannelList.count()]; for (quint16 i = 0; i < m_convChannelList.count(); ++i) { - m_minClamp[i] = mathToolbox->minChannelValue(m_convChannelList[i]); - m_maxClamp[i] = mathToolbox->maxChannelValue(m_convChannelList[i]); + m_minClamp[i] = mathToolbox.minChannelValue(m_convChannelList[i]); + m_maxClamp[i] = mathToolbox.maxChannelValue(m_convChannelList[i]); m_absoluteOffset[i] = (m_maxClamp[i] - m_minClamp[i]) * kernel->offset(); } qint32 row = srcPos.y(); qint32 col = srcPos.x(); // populate pixelPtrCacheCopy for starting position (0, 0) qint32 i = 0; typename _IteratorFactory_::HLineConstIterator hitInitSrc = _IteratorFactory_::createHLineConstIterator(src, col - m_khalfWidth, row - m_khalfHeight, m_kw, dataRect); for (quint32 krow = 0; krow < m_kh; ++krow) { do { const quint8* data = hitInitSrc->oldRawData(); loadPixelToCache(m_pixelPtrCacheCopy, data, i); ++i; } while (hitInitSrc->nextPixel()); hitInitSrc->nextRow(); } if (traversingDirection == Horizontal) { if(hasProgressUpdater) { this->m_progress->setRange(0, areaSize.height()); } typename _IteratorFactory_::HLineIterator hitDst = _IteratorFactory_::createHLineIterator(this->m_painter->device(), dstPos.x(), dstPos.y(), areaSize.width(), dataRect); typename _IteratorFactory_::HLineConstIterator hitSrc = _IteratorFactory_::createHLineConstIterator(src, srcPos.x(), srcPos.y(), areaSize.width(), dataRect); typename _IteratorFactory_::HLineConstIterator khitSrc = _IteratorFactory_::createHLineConstIterator(src, col - m_khalfWidth, row + m_khalfHeight, m_kw, dataRect); for (int prow = 0; prow < areaSize.height(); ++prow) { // reload cache from copy for (quint32 i = 0; i < m_cacheSize; ++i) memcpy(m_pixelPtrCache[i], m_pixelPtrCacheCopy[i], channelCount * sizeof(qreal)); typename _IteratorFactory_::VLineConstIterator kitSrc = _IteratorFactory_::createVLineConstIterator(src, col + m_khalfWidth, row - m_khalfHeight, m_kh, dataRect); for (int pcol = 0; pcol < areaSize.width(); ++pcol) { // write original channel values memcpy(hitDst->rawData(), hitSrc->oldRawData(), m_pixelSize); convolveCache(hitDst->rawData()); ++col; kitSrc->nextColumn(); hitDst->nextPixel(); hitSrc->nextPixel(); moveKernelRight(kitSrc, m_pixelPtrCache); } row++; khitSrc->nextRow(); hitDst->nextRow(); hitSrc->nextRow(); col = srcPos.x(); moveKernelDown(khitSrc, m_pixelPtrCacheCopy); if (hasProgressUpdater) { this->m_progress->setValue(prow); if (this->m_progress->interrupted()) { cleanUp(); return; } } } } else if (traversingDirection == Vertical) { if(hasProgressUpdater) { this->m_progress->setRange(0, areaSize.width()); } typename _IteratorFactory_::VLineIterator vitDst = _IteratorFactory_::createVLineIterator(this->m_painter->device(), dstPos.x(), dstPos.y(), areaSize.height(), dataRect); typename _IteratorFactory_::VLineConstIterator vitSrc = _IteratorFactory_::createVLineConstIterator(src, srcPos.x(), srcPos.y(), areaSize.height(), dataRect); typename _IteratorFactory_::VLineConstIterator kitSrc = _IteratorFactory_::createVLineConstIterator(src, col + m_khalfWidth, row - m_khalfHeight, m_kh, dataRect); for (int pcol = 0; pcol < areaSize.width(); pcol++) { // reload cache from copy for (quint32 i = 0; i < m_cacheSize; ++i) memcpy(m_pixelPtrCache[i], m_pixelPtrCacheCopy[i], channelCount * sizeof(qreal)); typename _IteratorFactory_::HLineConstIterator khitSrc = _IteratorFactory_::createHLineConstIterator(src, col - m_khalfWidth, row + m_khalfHeight, m_kw, dataRect); for (int prow = 0; prow < areaSize.height(); prow++) { // write original channel values memcpy(vitDst->rawData(), vitSrc->oldRawData(), m_pixelSize); convolveCache(vitDst->rawData()); ++row; khitSrc->nextRow(); vitDst->nextPixel(); vitSrc->nextPixel(); moveKernelDown(khitSrc, m_pixelPtrCache); } ++col; kitSrc->nextColumn(); vitDst->nextColumn(); vitSrc->nextColumn(); row = srcPos.y(); moveKernelRight(kitSrc, m_pixelPtrCacheCopy); if (hasProgressUpdater) { this->m_progress->setValue(pcol); if (this->m_progress->interrupted()) { cleanUp(); return; } } } } cleanUp(); } inline void limitValue(qreal *value, qreal lowBound, qreal highBound) { if (*value > highBound) { *value = highBound; } else if (*value < lowBound){ *value = lowBound; } } template inline qreal convolveOneChannelFromCache(quint8* dstPtr, quint32 channel, qreal additionalMultiplier = 0.0) { qreal interimConvoResult = 0; for (quint32 pIndex = 0; pIndex < m_cacheSize; ++pIndex) { qreal cacheValue = m_pixelPtrCache[pIndex][channel]; interimConvoResult += m_kernelData[m_cacheSize - pIndex - 1] * cacheValue; } qreal channelPixelValue; if (additionalMultiplierActive) { channelPixelValue = (interimConvoResult * m_kernelFactor + m_absoluteOffset[channel]) * additionalMultiplier; } else { channelPixelValue = interimConvoResult * m_kernelFactor + m_absoluteOffset[channel]; } limitValue(&channelPixelValue, m_minClamp[channel], m_maxClamp[channel]); const quint32 channelPos = m_convChannelList[channel]->pos(); m_fromDoubleFuncPtr[channel](dstPtr, channelPos, channelPixelValue); return channelPixelValue; } inline void convolveCache(quint8* dstPtr) { if (m_alphaCachePos >= 0) { qreal alphaValue = convolveOneChannelFromCache(dstPtr, m_alphaCachePos); if (alphaValue != 0.0) { qreal alphaValueInv = 1.0 / alphaValue; for (quint32 k = 0; k < m_convolveChannelsNo; ++k) { if (k == (quint32)m_alphaCachePos) continue; convolveOneChannelFromCache(dstPtr, k, alphaValueInv); } } else { for (quint32 k = 0; k < m_convolveChannelsNo; ++k) { if (k == (quint32)m_alphaCachePos) continue; const qreal zeroValue = 0.0; const quint32 channelPos = m_convChannelList[k]->pos(); m_fromDoubleFuncPtr[k](dstPtr, channelPos, zeroValue); } } } else { for (quint32 k = 0; k < m_convolveChannelsNo; ++k) { convolveOneChannelFromCache(dstPtr, k); } } } inline void moveKernelRight(typename _IteratorFactory_::VLineConstIterator& kitSrc, qreal **pixelPtrCache) { qreal** d = pixelPtrCache; for (quint32 krow = 0; krow < m_kh; ++krow) { qreal* first = *d; memmove(d, d + 1, (m_kw - 1) * sizeof(qreal *)); *(d + m_kw - 1) = first; d += m_kw; } qint32 i = m_kw - 1; do { const quint8* data = kitSrc->oldRawData(); loadPixelToCache(pixelPtrCache, data, i); i += m_kw; } while (kitSrc->nextPixel()); } inline void moveKernelDown(typename _IteratorFactory_::HLineConstIterator& kitSrc, qreal **pixelPtrCache) { quint8 **tmp = new quint8*[m_kw]; memcpy(tmp, pixelPtrCache, m_kw * sizeof(qreal *)); memmove(pixelPtrCache, pixelPtrCache + m_kw, (m_kw * m_kh - m_kw) * sizeof(quint8 *)); memcpy(pixelPtrCache + m_kw *(m_kh - 1), tmp, m_kw * sizeof(quint8 *)); delete[] tmp; qint32 i = m_kw * (m_kh - 1); do { const quint8* data = kitSrc->oldRawData(); loadPixelToCache(pixelPtrCache, data, i); i++; } while (kitSrc->nextPixel()); } void cleanUp() { for (quint32 c = 0; c < m_cacheSize; ++c) { delete[] m_pixelPtrCache[c]; delete[] m_pixelPtrCacheCopy[c]; } delete[] m_kernelData; delete[] m_pixelPtrCache; delete[] m_pixelPtrCacheCopy; delete[] m_minClamp; delete[] m_maxClamp; delete[] m_absoluteOffset; } private: quint32 m_kw, m_kh; quint32 m_khalfWidth, m_khalfHeight; quint32 m_convolveChannelsNo; quint32 m_cacheSize, m_pixelSize; int m_alphaCachePos; int m_alphaRealPos; qreal *m_kernelData; qreal** m_pixelPtrCache, ** m_pixelPtrCacheCopy; qreal* m_minClamp, *m_maxClamp, *m_absoluteOffset; qreal m_kernelFactor; QList m_convChannelList; QVector m_toDoubleFuncPtr; QVector m_fromDoubleFuncPtr; }; #endif diff --git a/krita/image/kis_math_toolbox.cpp b/krita/image/kis_math_toolbox.cpp index 59429ce116..edef8ddc99 100644 --- a/krita/image/kis_math_toolbox.cpp +++ b/krita/image/kis_math_toolbox.cpp @@ -1,246 +1,308 @@ /* * 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" #include #ifdef HAVE_OPENEXR #include #endif #include #include #include #include - -#include "kis_basic_math_toolbox.h" #include "kis_iterator_ng.h" -Q_GLOBAL_STATIC(KisMathToolboxRegistry, s_instance) - -KisMathToolbox::KisMathToolbox(KoID id) : m_id(id) -{ -} - -KisMathToolbox::~KisMathToolbox() -{ -} - -KisMathToolboxRegistry * KisMathToolboxRegistry::instance() -{ - return s_instance; -} - -KisMathToolboxRegistry::KisMathToolboxRegistry() -{ - add(new KisBasicMathToolbox()); -} - -KisMathToolboxRegistry::~KisMathToolboxRegistry() -{ - Q_FOREACH (const QString &id, keys()) { - delete get(id); - } - dbgRegistry << "Deleting KisMathToolboxRegistry"; -} +#include "math.h" template inline double toDouble(const quint8* data, int channelpos) { return (double)(*((T*)(data + channelpos))); } template void fromDouble(quint8* data, int channelpos, double v) { *((T*)(data + channelpos)) = (T)qRound(v); } template void fromDoubleF(quint8* data, int channelpos, double v) { *((T*)(data + channelpos)) = (T)v; } void KisMathToolbox::transformToFR(KisPaintDeviceSP src, KisFloatRepresentation* fr, const QRect& rect) { qint32 depth = src->colorSpace()->colorChannelCount(); QList cis = src->colorSpace()->channels(); // remove non-color channels for (qint32 c = 0; c < cis.count(); ++c) { if (cis[c]->channelType() != KoChannelInfo::COLOR) cis.removeAt(c--); } QVector f(depth); if (!getToDoubleChannelPtr(cis, f)) return; KisHLineConstIteratorSP srcIt = src->createHLineIteratorNG(rect.x(), rect.y(), rect.width()); for (int i = rect.y(); i < rect.height(); i++) { float *dstIt = fr->coeffs + (i - rect.y()) * fr->size * fr->depth; do { const quint8* v1 = srcIt->oldRawData(); for (int k = 0; k < depth; k++) { *dstIt = f[k](v1, cis[k]->pos()); ++dstIt; } } while (srcIt->nextPixel()); srcIt->nextRow(); } } bool KisMathToolbox::getToDoubleChannelPtr(QList cis, QVector& f) { qint32 channels = cis.count(); for (qint32 k = 0; k < channels; k++) { switch (cis[k]->channelValueType()) { case KoChannelInfo::UINT8: f[k] = toDouble; break; case KoChannelInfo::UINT16: f[k] = toDouble; break; #ifdef HAVE_OPENEXR case KoChannelInfo::FLOAT16: f[k] = toDouble; break; #endif case KoChannelInfo::FLOAT32: f[k] = toDouble; break; case KoChannelInfo::INT8: f[k] = toDouble; break; case KoChannelInfo::INT16: f[k] = toDouble; break; default: warnKrita << "Unsupported value type in KisMathToolbox"; return false; } } return true; } void KisMathToolbox::transformFromFR(KisPaintDeviceSP dst, KisFloatRepresentation* fr, const QRect& rect) { qint32 depth = dst->colorSpace()->colorChannelCount(); QList cis = dst->colorSpace()->channels(); // remove non-color channels for (qint32 c = 0; c < cis.count(); ++c) { if (cis[c]->channelType() != KoChannelInfo::COLOR) cis.removeAt(c--); } QVector f(depth); if (!getFromDoubleChannelPtr(cis, f)) return; KisHLineIteratorSP dstIt = dst->createHLineIteratorNG(rect.x(), rect.y(), rect.width()); for (int i = rect.y(); i < rect.height(); i++) { float *srcIt = fr->coeffs + (i - rect.y()) * fr->size * fr->depth; do { quint8* v1 = dstIt->rawData(); for (int k = 0; k < depth; k++) { f[k](v1, cis[k]->pos(), *srcIt); ++srcIt; } } while(dstIt->nextPixel()); dstIt->nextRow(); } } bool KisMathToolbox::getFromDoubleChannelPtr(QList cis, QVector& f) { qint32 channels = cis.count(); for (qint32 k = 0; k < channels; k++) { switch (cis[k]->channelValueType()) { case KoChannelInfo::UINT8: f[k] = fromDouble; break; case KoChannelInfo::UINT16: f[k] = fromDouble; break; #ifdef HAVE_OPENEXR case KoChannelInfo::FLOAT16: f[k] = fromDoubleF; break; #endif case KoChannelInfo::FLOAT32: f[k] = fromDoubleF; break; case KoChannelInfo::INT8: f[k] = fromDouble; break; case KoChannelInfo::INT16: f[k] = fromDouble; break; default: warnKrita << "Unsupported value type in KisMathToolbox"; return false; } } return true; } double KisMathToolbox::minChannelValue(KoChannelInfo *c) { switch (c->channelValueType()) { case KoChannelInfo::UINT8 : return KoColorSpaceMathsTraits::min; case KoChannelInfo::UINT16 : return KoColorSpaceMathsTraits::min; case KoChannelInfo::UINT32 : return KoColorSpaceMathsTraits::min; #ifdef HAVE_OPENEXR case KoChannelInfo::FLOAT16 : return KoColorSpaceMathsTraits::min; #endif case KoChannelInfo::FLOAT32 : return KoColorSpaceMathsTraits::min; case KoChannelInfo::FLOAT64 : return KoColorSpaceMathsTraits::min; case KoChannelInfo::INT8 : return 127; case KoChannelInfo::INT16 : return KoColorSpaceMathsTraits::min; default: return 0; } } double KisMathToolbox::maxChannelValue(KoChannelInfo *c) { switch (c->channelValueType()) { case KoChannelInfo::UINT8 : return KoColorSpaceMathsTraits::max; case KoChannelInfo::UINT16 : return KoColorSpaceMathsTraits::max; case KoChannelInfo::UINT32 : return KoColorSpaceMathsTraits::max; #ifdef HAVE_OPENEXR case KoChannelInfo::FLOAT16 : return KoColorSpaceMathsTraits::max; #endif case KoChannelInfo::FLOAT32 : return KoColorSpaceMathsTraits::max; case KoChannelInfo::FLOAT64 : return KoColorSpaceMathsTraits::max; case KoChannelInfo::INT8 : return -128; case KoChannelInfo::INT16 : return KoColorSpaceMathsTraits::max; default: return 0; } } +void KisMathToolbox::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; + } + } + 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 KisMathToolbox::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; + } + } + 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* KisMathToolbox::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 KisMathToolbox::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/image/kis_math_toolbox.h b/krita/image/kis_math_toolbox.h index a25eaeb1d6..1ad6fbd20d 100644 --- a/krita/image/kis_math_toolbox.h +++ b/krita/image/kis_math_toolbox.h @@ -1,184 +1,145 @@ /* * 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 #include -#include +#include + #include #include "kis_types.h" -#include #include "kis_paint_device.h" #ifdef _MSC_VER #pragma warning(disable: 4290) // disable "C++ exception specification ignored" warning #endif #pragma GCC diagnostic ignored "-Wcast-align" typedef double(*PtrToDouble)(const quint8*, int); typedef void (*PtrFromDouble)(quint8*, int, double); -class KRITAIMAGE_EXPORT KisMathToolbox : public QObject +class KRITAIMAGE_EXPORT KisMathToolbox { - 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 (quint32 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(KoID id); - - virtual ~KisMathToolbox(); - -public: - - inline QString id() { - return m_id.id(); - } - - inline QString name() { - return m_id.name(); - } - /** - * This function initialize a wavelet structure + * This function initializes 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; + KisWavelet* fastWaveletTransformation(KisPaintDeviceSP src, const QRect&, KisWavelet* buff = 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; + void fastWaveletUntransformation(KisPaintDeviceSP dst, const QRect&, KisWavelet* wav, KisWavelet* buff = 0); bool getToDoubleChannelPtr(QList cis, QVector& f); bool getFromDoubleChannelPtr(QList cis, QVector& f); double minChannelValue(KoChannelInfo *); double maxChannelValue(KoChannelInfo *); -Q_SIGNALS: - - void nextStep(); +private: -protected: + void wavetrans(KisWavelet* wav, KisWavelet* buff, uint halfsize); + void waveuntrans(KisWavelet* wav, KisWavelet* buff, uint halfsize); /** * This function transform a paint device into a KisFloatRepresentation, this function is colorspace independent, * for Wavelet, Pyramid and FFT the data is always 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 independent, * for Wavelet, Pyramid and FFT the data is always the exact value of the channel stored in a float. */ void transformFromFR(KisPaintDeviceSP dst, KisFloatRepresentation*, const QRect&); -private: - - KoID m_id; - }; -class KRITAIMAGE_EXPORT KisMathToolboxRegistry - : public KoGenericRegistry -{ - -public: - KisMathToolboxRegistry(); - virtual ~KisMathToolboxRegistry(); - static KisMathToolboxRegistry * instance(); - -private: - - KisMathToolboxRegistry(const KisMathToolboxRegistry&); - KisMathToolboxRegistry operator=(const KisMathToolboxRegistry&); -}; - - 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) ; qint32 depth = src->colorSpace()->colorChannelCount(); 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/image/tests/CMakeLists.txt b/krita/image/tests/CMakeLists.txt index 5a209941ac..56aa1bb857 100644 --- a/krita/image/tests/CMakeLists.txt +++ b/krita/image/tests/CMakeLists.txt @@ -1,679 +1,673 @@ # cmake in some versions for some not yet known reasons fails to run automoc # on random targets (changing target names already has an effect) # As temporary workaround skipping build of tests on these versions for now # See https://mail.kde.org/pipermail/kde-buildsystem/2015-June/010819.html # extend range of affected cmake versions as needed if(NOT ${CMAKE_VERSION} VERSION_LESS 3.1.3 AND NOT ${CMAKE_VERSION} VERSION_GREATER 3.2.3) message(WARNING "Skipping krita/image/tests, CMake in at least versions 3.1.3 - 3.2.3 seems to have a problem with automoc. \n(FRIENDLY REMINDER: PLEASE DON'T BREAK THE TESTS!)") return() endif() # set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} ) include_directories( ${CMAKE_SOURCE_DIR}/krita/image/metadata ${CMAKE_SOURCE_DIR}/krita/sdk/tests ) macro_add_unittest_definitions() set(KisRandomGeneratorDemoSources kis_random_generator_demo.cpp kimageframe.cpp) ki18n_wrap_ui(KisRandomGeneratorDemoSources kis_random_generator_demo.ui) kde4_add_executable(KisRandomGeneratorDemo ${KisRandomGeneratorDemoSources}) target_link_libraries(KisRandomGeneratorDemo kritaimage ) ########### next target ############### set(kis_base_node_test_SRCS kis_base_node_test.cpp ) kde4_add_unit_test(KisBaseNodeTest TESTNAME krita-image-BaseNodeTest ${kis_base_node_test_SRCS}) target_link_libraries(KisBaseNodeTest kritaimage Qt5::Test) ########### next target ############### set(kis_fast_math_test_SRCS kis_fast_math_test.cpp ) kde4_add_unit_test(KisFastMathTest TESTNAME krita-image-FastMathTest ${kis_fast_math_test_SRCS}) target_link_libraries(KisFastMathTest kritaimage Qt5::Test) ########### next target ############### set(kis_node_test_SRCS kis_node_test.cpp ) kde4_add_unit_test(KisNodeTest TESTNAME krita-image-Node-Test ${kis_node_test_SRCS}) target_link_libraries(KisNodeTest kritaimage Qt5::Test) ########### next target ############### set(kis_node_facade_test_SRCS kis_node_facade_test.cpp ) kde4_add_unit_test(KisNodeFacadeTest TESTNAME krita-image-NodeFacadeTest ${kis_node_facade_test_SRCS}) target_link_libraries(KisNodeFacadeTest kritaimage Qt5::Test) ########### next target ############### set(kis_paint_device_test_SRCS kis_paint_device_test.cpp ) kde4_add_unit_test(KisPaintDeviceTest TESTNAME krita-image-KisPaintDeviceTest ${kis_paint_device_test_SRCS}) target_link_libraries(KisPaintDeviceTest kritaimage kritaodf Qt5::Test) ########### next target ############### set(kis_fixed_paint_device_test_SRCS kis_fixed_paint_device_test.cpp ) kde4_add_unit_test(KisFixedPaintDeviceTest TESTNAME krita-image-KisFixedPaintDeviceTest ${kis_fixed_paint_device_test_SRCS}) target_link_libraries(KisFixedPaintDeviceTest kritaimage Qt5::Test) ########### next target ############### set(kis_layer_test_SRCS kis_layer_test.cpp ) kde4_add_unit_test(KisLayerTest TESTNAME krita-image-KisLayerTest ${kis_layer_test_SRCS}) target_link_libraries(KisLayerTest kritaimage Qt5::Test) ########### next target ############### set(kis_effect_mask_test_SRCS kis_effect_mask_test.cpp ) kde4_add_unit_test(KisEffectMaskTest TESTNAME krita-image-KisEffectMaskTest ${kis_effect_mask_test_SRCS}) target_link_libraries(KisEffectMaskTest kritaimage Qt5::Test) ########### next target ############### set(kis_iterator_test_SRCS kis_iterator_test.cpp ) kde4_add_unit_test(KisIteratorTest TESTNAME krita-image-KisIteratorTest ${kis_iterator_test_SRCS}) target_link_libraries(KisIteratorTest kritaimage Qt5::Test) ########### next target ############### set(kis_painter_test_SRCS kis_painter_test.cpp ) kde4_add_unit_test(KisPainterTest TESTNAME krita-image-KisPainterTest ${kis_painter_test_SRCS}) target_link_libraries(KisPainterTest kritaimage Qt5::Test) ########### next target ############### set(kis_selection_test_SRCS kis_selection_test.cpp ) kde4_add_unit_test(KisSelectionTest TESTNAME krita-image-SelectionTest ${kis_selection_test_SRCS}) target_link_libraries(KisSelectionTest kritaimage Qt5::Test) ########### next target ############### set(kis_count_visitor_test_SRCS kis_count_visitor_test.cpp ) kde4_add_unit_test(KisCountVisitorTest TESTNAME krita-image-KisCountVisitorTest ${kis_count_visitor_test_SRCS}) target_link_libraries(KisCountVisitorTest kritaimage Qt5::Test) ########### next target ############### set(kis_projection_test_SRCS kis_projection_test.cpp ) kde4_add_unit_test(KisProjectionTest TESTNAME krita-image-KisProjectionTest ${kis_projection_test_SRCS}) target_link_libraries(KisProjectionTest kritaimage Qt5::Test) ########### next target ############### set(kis_properties_configuration_test_SRCS kis_properties_configuration_test.cpp ) kde4_add_unit_test(Kis_Properties_Configuration_Test TESTNAME krita-image-properties-configuration-Test ${kis_properties_configuration_test_SRCS}) target_link_libraries(Kis_Properties_Configuration_Test kritaimage Qt5::Test) ########### next target ############### set(kis_transaction_test_SRCS kis_transaction_test.cpp ) kde4_add_unit_test(KisTransactionTest TESTNAME krita-image-KisTransactionTest ${kis_transaction_test_SRCS}) target_link_libraries(KisTransactionTest kritaimage Qt5::Test) ########### next target ############### set(kis_pixel_selection_test_SRCS kis_pixel_selection_test.cpp ) kde4_add_unit_test(KisPixelSelectionTest TESTNAME krita-image-KisPixelSelectionTest ${kis_pixel_selection_test_SRCS}) target_link_libraries(KisPixelSelectionTest kritaimage Qt5::Test) ########### next target ############### set(kis_group_layer_test_SRCS kis_group_layer_test.cpp ) kde4_add_unit_test(KisGroupLayerTest TESTNAME krita-image-KisGroupLayerTest ${kis_group_layer_test_SRCS}) target_link_libraries(KisGroupLayerTest kritaimage Qt5::Test) ########### next target ############### set(kis_filter_mask_test_SRCS kis_filter_mask_test.cpp ) kde4_add_unit_test(KisFilterMaskTest TESTNAME krita-image-KisFilterMaskTest ${kis_filter_mask_test_SRCS}) target_link_libraries(KisFilterMaskTest kritaimage Qt5::Test) ########### next target ############### set(kis_transform_mask_test_SRCS kis_transform_mask_test.cpp ) kde4_add_unit_test(KisTransformMaskTest TESTNAME krita-image-KisTransformMaskTest ${kis_transform_mask_test_SRCS}) target_link_libraries(KisTransformMaskTest kritaimage Qt5::Test) ########### next target ############### set(kis_paint_layer_test_SRCS kis_paint_layer_test.cpp ) kde4_add_unit_test(KisPaintLayerTest TESTNAME krita-image-KisPaintLayerTest ${kis_paint_layer_test_SRCS}) target_link_libraries(KisPaintLayerTest kritaimage Qt5::Test) ########### next target ############### set(kis_adjustment_layer_test_SRCS kis_adjustment_layer_test.cpp ) kde4_add_unit_test(KisAdjustmentLayerTest TESTNAME krita-image-KisAdjustmentLayerTest ${kis_adjustment_layer_test_SRCS}) target_link_libraries(KisAdjustmentLayerTest kritaimage Qt5::Test) ########### next target ############### set(kis_annotation_test_SRCS kis_annotation_test.cpp ) kde4_add_unit_test(KisAnnotationTest TESTNAME krita-image-KisAnnotationTest ${kis_annotation_test_SRCS}) target_link_libraries(KisAnnotationTest kritaimage Qt5::Test) ########### next target ############### -set(kis_basic_math_toolbox_test_SRCS kis_basic_math_toolbox_test.cpp ) -kde4_add_unit_test(KisBasicMathToolboxTest TESTNAME krita-image-KisBasicMathToolboxTest ${kis_basic_math_toolbox_test_SRCS}) -target_link_libraries(KisBasicMathToolboxTest kritaimage Qt5::Test) - -########### next target ############### - set(kis_bookmarked_configuration_manager_test_SRCS kis_bookmarked_configuration_manager_test.cpp ) kde4_add_unit_test(KisBookmarkedConfigurationManagerTest TESTNAME krita-image-KisBookmarkedConfigurationManagerTest ${kis_bookmarked_configuration_manager_test_SRCS}) target_link_libraries(KisBookmarkedConfigurationManagerTest kritaimage Qt5::Test) ########### next target ############### set(kis_change_profile_visitor_test_SRCS kis_change_profile_visitor_test.cpp ) kde4_add_unit_test(KisChangeProfileVisitorTest TESTNAME krita-image-KisChangeProfileVisitorTest ${kis_change_profile_visitor_test_SRCS}) target_link_libraries(KisChangeProfileVisitorTest kritaimage Qt5::Test) ########### next target ############### set(kis_clone_layer_test_SRCS kis_clone_layer_test.cpp ) kde4_add_unit_test(KisCloneLayerTest TESTNAME krita-image-KisCloneLayerTest ${kis_clone_layer_test_SRCS}) target_link_libraries(KisCloneLayerTest kritaimage Qt5::Test) ########### next target ############### set(kis_colorspace_convert_visitor_test_SRCS kis_colorspace_convert_visitor_test.cpp ) kde4_add_unit_test(KisColorspaceConvertVisitorTest TESTNAME krita-image-KisColorspaceConvertVisitorTest ${kis_colorspace_convert_visitor_test_SRCS}) target_link_libraries(KisColorspaceConvertVisitorTest kritaimage Qt5::Test) ########### next target ############### set(kis_convolution_painter_test_SRCS kis_convolution_painter_test.cpp ) kde4_add_unit_test(KisConvolutionPainterTest TESTNAME krita-image-KisConvolutionPainterTest ${kis_convolution_painter_test_SRCS}) target_link_libraries(KisConvolutionPainterTest kritaimage Qt5::Test) ########### next target ############### set(kis_crop_processing_visitor_test_SRCS kis_crop_processing_visitor_test.cpp ) kde4_add_unit_test(KisCropProcessingVisitorTest TESTNAME krita-image-KisCropProcessingVisitorTest ${kis_crop_processing_visitor_test_SRCS}) target_link_libraries(KisCropProcessingVisitorTest kritaimage Qt5::Test) ########### next target ############### set(kis_processing_applicator_test_SRCS kis_processing_applicator_test.cpp ) kde4_add_unit_test(KisProcessingApplicatorTest TESTNAME krita-image-KisProcessingApplicatorTest ${kis_processing_applicator_test_SRCS}) target_link_libraries(KisProcessingApplicatorTest kritaimage Qt5::Test) ########### next target ############### set(kis_datamanager_test_SRCS kis_datamanager_test.cpp ) kde4_add_unit_test(KisDatamanagerTest TESTNAME krita-image-KisDatamanagerTest ${kis_datamanager_test_SRCS}) target_link_libraries(KisDatamanagerTest kritaimage Qt5::Test) ########### next target ############### set(kis_fill_painter_test_SRCS kis_fill_painter_test.cpp ) kde4_add_unit_test(KisFillPainterTest TESTNAME krita-image-KisFillPainterTest ${kis_fill_painter_test_SRCS}) target_link_libraries(KisFillPainterTest kritaimage Qt5::Test) ########### next target ############### set(kis_filter_configuration_test_SRCS kis_filter_configuration_test.cpp ) kde4_add_unit_test(KisFilterConfigurationTest TESTNAME krita-image-KisFilterConfigurationTest ${kis_filter_configuration_test_SRCS}) target_link_libraries(KisFilterConfigurationTest kritaimage Qt5::Test) ########### next target ############### set(kis_filter_test_SRCS kis_filter_test.cpp ) kde4_add_unit_test(KisFilterTest TESTNAME krita-image-KisFilterTest ${kis_filter_test_SRCS}) target_link_libraries(KisFilterTest kritaimage Qt5::Test) ########### next target ############### set(kis_filter_processing_information_test_SRCS kis_filter_processing_information_test.cpp ) kde4_add_unit_test(KisFilterProcessingInformationTest TESTNAME krita-image-KisFilterProcessingInformationTest ${kis_filter_processing_information_test_SRCS}) target_link_libraries(KisFilterProcessingInformationTest kritaimage Qt5::Test) ########### next target ############### set(kis_filter_registry_test_SRCS kis_filter_registry_test.cpp ) kde4_add_unit_test(KisFilterRegistryTest TESTNAME krita-image-KisFilterRegistryTest ${kis_filter_registry_test_SRCS}) target_link_libraries(KisFilterRegistryTest kritaimage Qt5::Test) ########### next target ############### set(kis_filter_strategy_test_SRCS kis_filter_strategy_test.cpp ) kde4_add_unit_test(KisFilterStrategyTest TESTNAME krita-image-KisFilterStrategyTest ${kis_filter_strategy_test_SRCS}) target_link_libraries(KisFilterStrategyTest kritaimage Qt5::Test) ########### next target ############### set(kis_gradient_painter_test_SRCS kis_gradient_painter_test.cpp ) kde4_add_unit_test(KisGradientPainterTest TESTNAME krita-image-KisGradientPainterTest ${kis_gradient_painter_test_SRCS}) target_link_libraries(KisGradientPainterTest kritaimage Qt5::Test) ########### next target ############### set(kis_histogram_test_SRCS kis_histogram_test.cpp ) kde4_add_unit_test(KisHistogramTest TESTNAME krita-image-KisHistogramTest ${kis_histogram_test_SRCS}) target_link_libraries(KisHistogramTest kritaimage Qt5::Test) ########### next target ############### set(kis_image_commands_test_SRCS kis_image_commands_test.cpp ) kde4_add_unit_test(KisImageCommandsTest TESTNAME krita-image-KisImageCommandsTest ${kis_image_commands_test_SRCS}) target_link_libraries(KisImageCommandsTest kritaimage Qt5::Test) ########### next target ############### set(kis_image_test_SRCS kis_image_test.cpp ) kde4_add_unit_test(KisImageTest TESTNAME krita-image-KisImageTest ${kis_image_test_SRCS}) target_link_libraries(KisImageTest kritaimage Qt5::Test) ########### next target ############### set(kis_image_signal_router_test_SRCS kis_image_signal_router_test.cpp ) kde4_add_unit_test(KisImageSignalRouterTest TESTNAME krita-image-KisImageSignalRouterTest ${kis_image_signal_router_test_SRCS}) target_link_libraries(KisImageSignalRouterTest kritaimage Qt5::Test) ########### next target ############### set(kis_iterators_ng_test_SRCS kis_iterators_ng_test.cpp ) kde4_add_unit_test(KisIteratorsNGTest TESTNAME krita-image-KisIteratorsNGTest ${kis_iterators_ng_test_SRCS}) target_link_libraries(KisIteratorsNGTest kritaimage Qt5::Test) ########### next target ############### set(kis_iterator_benchmark_SRCS kis_iterator_benchmark.cpp ) kde4_add_unit_test(KisIteratorBenchmark TESTNAME krita-image-KisIteratorBenchmark ${kis_iterator_benchmark_SRCS}) target_link_libraries(KisIteratorBenchmark kritaimage Qt5::Test) ########### next target ############### set(kis_layer_commands_test_SRCS kis_layer_commands_test.cpp ) kde4_add_unit_test(KisLayerCommandsTest TESTNAME krita-image-KisLayerCommandsTest ${kis_layer_commands_test_SRCS}) target_link_libraries(KisLayerCommandsTest kritaimage Qt5::Test) ########### next target ############### set(kis_walkers_test_SRCS kis_walkers_test.cpp ) kde4_add_unit_test(KisWalkersTest TESTNAME krita-image-KisWalkersTest ${kis_walkers_test_SRCS}) target_link_libraries(KisWalkersTest kritaimage Qt5::Test) ########### next target ############### set(kis_async_merger_test_SRCS kis_async_merger_test.cpp ) kde4_add_unit_test(KisAsyncMergerTest TESTNAME krita-image-KisAsyncMergerTest ${kis_async_merger_test_SRCS}) target_link_libraries(KisAsyncMergerTest kritaimage Qt5::Test) ########### next target ############### set(kis_updater_context_test_SRCS kis_updater_context_test.cpp ) kde4_add_unit_test(KisUpdaterContextTest TESTNAME krita-image-KisUpdaterContextTest ${kis_updater_context_test_SRCS}) target_link_libraries(KisUpdaterContextTest kritaimage Qt5::Test) ########### next target ############### set(kis_simple_update_queue_test_SRCS kis_simple_update_queue_test.cpp ) kde4_add_unit_test(KisSimpleUpdateQueueTest TESTNAME krita-image-KisSimpleUpdateQueueTest ${kis_simple_update_queue_test_SRCS}) target_link_libraries(KisSimpleUpdateQueueTest kritaimage Qt5::Test) ########### next target ############### set(kis_update_scheduler_test_SRCS kis_update_scheduler_test.cpp ) kde4_add_unit_test(KisUpdateSchedulerTest TESTNAME krita-image-KisUpdateSchedulerTest ${kis_update_scheduler_test_SRCS}) target_link_libraries(KisUpdateSchedulerTest kritaimage Qt5::Test) ########### next target ############### set(kis_stroke_test_SRCS kis_stroke_test.cpp ) kde4_add_unit_test(KisStrokeTest TESTNAME krita-image-KisStrokeTest ${kis_stroke_test_SRCS}) target_link_libraries(KisStrokeTest kritaimage Qt5::Test) ########### next target ############### set(kis_simple_stroke_strategy_test_SRCS kis_simple_stroke_strategy_test.cpp ) kde4_add_unit_test(KisSimpleStrokeStrategyTest TESTNAME krita-image-KisSimpleStrokeStrategyTest ${kis_simple_stroke_strategy_test_SRCS}) target_link_libraries(KisSimpleStrokeStrategyTest kritaimage Qt5::Test) ########### next target ############### set(kis_stroke_strategy_undo_command_based_test_SRCS kis_stroke_strategy_undo_command_based_test.cpp ) kde4_add_unit_test(KisStrokeStrategyUndoCommandBasedTest TESTNAME krita-image-KisStrokeStrategyUndoCommandBasedTest ${kis_stroke_strategy_undo_command_based_test_SRCS}) target_link_libraries(KisStrokeStrategyUndoCommandBasedTest kritaimage Qt5::Test) ########### next target ############### set(kis_strokes_queue_test_SRCS kis_strokes_queue_test.cpp ) kde4_add_unit_test(KisStrokesQueueTest TESTNAME krita-image-KisStrokesQueueTest ${kis_strokes_queue_test_SRCS}) target_link_libraries(KisStrokesQueueTest kritaimage Qt5::Test) ########### next target ############### set(kis_queues_progress_updater_test_SRCS kis_queues_progress_updater_test.cpp ) kde4_add_unit_test(KisQueuesProgressUpdaterTest TESTNAME krita-image-KisQueuesProgressUpdaterTest ${kis_queues_progress_updater_test_SRCS}) target_link_libraries(KisQueuesProgressUpdaterTest kritaimage Qt5::Test) ########### next target ############### set(kis_macro_test_SRCS kis_macro_test.cpp ) kde4_add_unit_test(KisMacroTest TESTNAME krita-image-KisMacroTest ${kis_macro_test_SRCS}) target_link_libraries(KisMacroTest kritaimage Qt5::Test) ########### next target ############### set(kis_mask_test_SRCS kis_mask_test.cpp ) kde4_add_unit_test(KisMaskTest TESTNAME krita-image-KisMaskTest ${kis_mask_test_SRCS}) target_link_libraries(KisMaskTest kritaimage Qt5::Test) ########### next target ############### set(kis_math_toolbox_test_SRCS kis_math_toolbox_test.cpp ) kde4_add_unit_test(KisMathToolboxTest TESTNAME krita-image-KisMathToolboxTest ${kis_math_toolbox_test_SRCS}) target_link_libraries(KisMathToolboxTest kritaimage Qt5::Test) ########### next target ############### set(kis_name_server_test_SRCS kis_name_server_test.cpp ) kde4_add_unit_test(KisNameServerTest TESTNAME krita-image-KisNameServerTest ${kis_name_server_test_SRCS}) target_link_libraries(KisNameServerTest kritaimage Qt5::Test) ########### next target ############### set(kis_node_commands_test_SRCS kis_node_commands_test.cpp ) kde4_add_unit_test(KisNodeCommandsTest TESTNAME krita-image-KisNodeCommandsTest ${kis_node_commands_test_SRCS}) target_link_libraries(KisNodeCommandsTest kritaimage Qt5::Test) ########### next target ############### set(kis_node_graph_listener_test_SRCS kis_node_graph_listener_test.cpp ) kde4_add_unit_test(KisNodeGraphListenerTest TESTNAME krita-image-KisNodeGraphListenerTest ${kis_node_graph_listener_test_SRCS}) target_link_libraries(KisNodeGraphListenerTest kritaimage Qt5::Test) ########### next target ############### set(kis_node_visitor_test_SRCS kis_node_visitor_test.cpp ) kde4_add_unit_test(KisNodeVisitorTest TESTNAME krita-image-KisNodeVisitorTest ${kis_node_visitor_test_SRCS}) target_link_libraries(KisNodeVisitorTest kritaimage Qt5::Test) ########### next target ############### set(kis_paint_information_test_SRCS kis_paint_information_test.cpp ) kde4_add_unit_test(KisPaintInformationTest TESTNAME krita-image-KisPaintInformationTest ${kis_paint_information_test_SRCS}) target_link_libraries(KisPaintInformationTest kritaimage Qt5::Test) ########### next target ############### set(kis_paintop_test_SRCS kis_paintop_test.cpp ) kde4_add_unit_test(KisPaintopTest TESTNAME krita-image-KisPaintopTest ${kis_paintop_test_SRCS}) target_link_libraries(KisPaintopTest kritaimage Qt5::Test) ########### next target ############### set(kis_pattern_test_SRCS kis_pattern_test.cpp ) kde4_add_unit_test(KoPatternTest TESTNAME krita-image-KoPatternTest ${kis_pattern_test_SRCS}) target_link_libraries(KoPatternTest kritaimage Qt5::Test) ########### next target ############### set(kis_perspective_grid_test_SRCS kis_perspective_grid_test.cpp ) kde4_add_unit_test(KisPerspectiveGridTest TESTNAME krita-image-KisPerspectiveGridTest ${kis_perspective_grid_test_SRCS}) target_link_libraries(KisPerspectiveGridTest kritaimage Qt5::Test) ########### next target ############### set(kis_recorded_action_factory_registry_test_SRCS kis_recorded_action_factory_registry_test.cpp ) kde4_add_unit_test(KisRecordedActionFactoryRegistryTest TESTNAME krita-image-KisRecordedActionFactoryRegistryTest ${kis_recorded_action_factory_registry_test_SRCS}) target_link_libraries(KisRecordedActionFactoryRegistryTest kritaimage Qt5::Test) ########### next target ############### set(kis_recorded_action_test_SRCS kis_recorded_action_test.cpp ) kde4_add_unit_test(KisRecordedActionTest TESTNAME krita-image-KisRecordedActionTest ${kis_recorded_action_test_SRCS}) target_link_libraries(KisRecordedActionTest kritaimage Qt5::Test) ########### next target ############### set(kis_recorded_filter_action_test_SRCS kis_recorded_filter_action_test.cpp ) kde4_add_unit_test(KisRecordedFilterActionTest TESTNAME krita-image-KisRecordedFilterActionTest ${kis_recorded_filter_action_test_SRCS}) target_link_libraries(KisRecordedFilterActionTest kritaimage Qt5::Test) ########### next target ############### set(kis_selection_mask_test_SRCS kis_selection_mask_test.cpp ) kde4_add_unit_test(KisSelectionMaskTest TESTNAME krita-image-KisSelectionMaskTest ${kis_selection_mask_test_SRCS}) target_link_libraries(KisSelectionMaskTest kritaimage Qt5::Test) ########### next target ############### set(kis_shared_ptr_test_SRCS kis_shared_ptr_test.cpp ) kde4_add_unit_test(KisSharedPtrTest TESTNAME krita-image-KisSharedPtrTest ${kis_shared_ptr_test_SRCS}) target_link_libraries(KisSharedPtrTest kritaimage Qt5::Test) ########### next target ############### set(kis_transform_worker_test_SRCS kis_transform_worker_test.cpp ) kde4_add_unit_test(KisTransformWorkerTest TESTNAME krita-image-KisTransformWorkerTest ${kis_transform_worker_test_SRCS}) target_link_libraries(KisTransformWorkerTest kritaimage Qt5::Test) ########### next target ############### set(kis_perspective_transform_worker_test_SRCS kis_perspective_transform_worker_test.cpp ) kde4_add_unit_test(KisPerspectiveTransformWorkerTest TESTNAME krita-image-KisPerspectiveTransformWorkerTest ${kis_perspective_transform_worker_test_SRCS}) target_link_libraries(KisPerspectiveTransformWorkerTest kritaimage Qt5::Test) ########### next target ############### set(kis_bsplines_test_SRCS kis_bsplines_test.cpp ) kde4_add_unit_test(KisBSplinesTest TESTNAME krita-image-KisBSplinesTest ${kis_bsplines_test_SRCS}) target_link_libraries(KisBSplinesTest kritaimage Qt5::Test) ########### next target ############### set(kis_warp_transform_worker_test_SRCS kis_warp_transform_worker_test.cpp) kde4_add_unit_test(KisWarpTransformWorkerTest TESTNAME krita-image-KisWarpTransformWorkerTest ${kis_warp_transform_worker_test_SRCS}) target_link_libraries(KisWarpTransformWorkerTest kritaimage Qt5::Test) ########### next target ############### set(kis_cage_transform_worker_test_SRCS kis_cage_transform_worker_test.cpp) kde4_add_unit_test(KisCageTransformWorkerTest TESTNAME krita-image-KisCageTransformWorkerTest ${kis_cage_transform_worker_test_SRCS}) target_link_libraries(KisCageTransformWorkerTest kritaimage Qt5::Test) ########### next target ############### set(kis_liquify_transform_worker_test_SRCS kis_liquify_transform_worker_test.cpp) kde4_add_unit_test(KisLiquifyTransformWorkerTest TESTNAME krita-image-KisLiquifyTransformWorkerTest ${kis_liquify_transform_worker_test_SRCS}) target_link_libraries(KisLiquifyTransformWorkerTest kritaimage Qt5::Test) ########### next target ############### set(kis_transparency_mask_test_SRCS kis_transparency_mask_test.cpp ) kde4_add_unit_test(KisTransparencyMaskTest TESTNAME krita-image-KisTransparencyMaskTest ${kis_transparency_mask_test_SRCS}) target_link_libraries(KisTransparencyMaskTest kritaimage Qt5::Test) ########### next target ############### set(kis_types_test_SRCS kis_types_test.cpp ) kde4_add_unit_test(KisTypesTest TESTNAME krita-image-KisTypesTest ${kis_types_test_SRCS}) target_link_libraries(KisTypesTest kritaimage Qt5::Test) ########### next target ############### set(kis_vec_test_SRCS kis_vec_test.cpp ) kde4_add_unit_test(KisVecTest TESTNAME krita-image-KisVecTest ${kis_vec_test_SRCS}) target_link_libraries(KisVecTest kritaimage Qt5::Test) ########### next target ############### set(kis_filter_config_widget_test_SRCS kis_filter_config_widget_test.cpp ) kde4_add_unit_test(KisFilterConfigWidgetTest TESTNAME krita-image-KisFilterConfigWidgetTest ${kis_filter_config_widget_test_SRCS}) target_link_libraries(KisFilterConfigWidgetTest kritaimage Qt5::Test) ########### next target ############### set(kis_meta_data_test_SRCS kis_meta_data_test.cpp ) kde4_add_unit_test(KisMetaDataTest TESTNAME krita-image-KisMetaDataTest ${kis_meta_data_test_SRCS}) target_link_libraries(KisMetaDataTest kritaimage Qt5::Test) ########### next target ############### set(kis_random_generator_test_SRCS kis_random_generator_test.cpp ) kde4_add_unit_test(KisRandomGeneratorTest TESTNAME krita-image-KisRandomGeneratorTest ${kis_random_generator_test_SRCS}) target_link_libraries(KisRandomGeneratorTest kritaimage Qt5::Test) ########### next target ############### set(kis_mask_generator_test_SRCS kis_mask_generator_test.cpp ) kde4_add_unit_test(KisMaskGeneratorTest TESTNAME krita-image-KisMaskGeneratorTest ${kis_mask_generator_test_SRCS}) target_link_libraries(KisMaskGeneratorTest kritaimage Qt5::Test) ########### next target ############### #set(kis_cs_conversion_test_SRCS kis_cs_conversion_test.cpp ) #kde4_add_unit_test(KisCsConversionTest TESTNAME krita-image-KisCsConversionTest ${kis_cs_conversion_test_SRCS}) #target_link_libraries(KisCsConversionTest kritaimage Qt5::Test) ########### next target ############### set(kis_cubic_curve_test_SRCS kis_cubic_curve_test.cpp ) kde4_add_unit_test(KisCubicCurveTest TESTNAME krita-image-KisCubicCurveTest ${kis_cubic_curve_test_SRCS}) target_link_libraries(KisCubicCurveTest kritaimage Qt5::Test) ########### next target ############### set(kis_node_query_path_test_SRCS kis_node_query_path_test.cpp ) kde4_add_unit_test(KisNodeQueryPathTest TESTNAME krita-image-KisNodeQueryPathTest ${kis_node_query_path_test_SRCS}) target_link_libraries(KisNodeQueryPathTest kritaimage Qt5::Test) ########### next target ############### set(kis_processings_test_SRCS kis_processings_test.cpp ) kde4_add_unit_test(KisProcessingsTest TESTNAME krita-image-KisProcessingsTest ${kis_processings_test_SRCS}) target_link_libraries(KisProcessingsTest kritaimage Qt5::Test) ########### next target ############### set(kis_fixed_point_maths_test_SRCS kis_fixed_point_maths_test.cpp ) kde4_add_unit_test(KisFixedPointMathsTest TESTNAME krita-image-KisFixedPointMathsTest ${kis_fixed_point_maths_test_SRCS}) target_link_libraries(KisFixedPointMathsTest kritaimage Qt5::Test) ########### next target ############### set(kis_filter_weights_buffer_test_SRCS kis_filter_weights_buffer_test.cpp ) kde4_add_unit_test(KisFilterWeightsBufferTest TESTNAME krita-image-KisFilterWeightsBufferTest ${kis_filter_weights_buffer_test_SRCS}) target_link_libraries(KisFilterWeightsBufferTest kritaimage Qt5::Test) ########### next target ############### set(kis_filter_weights_applicator_test_SRCS kis_filter_weights_applicator_test.cpp ) kde4_add_unit_test(KisFilterWeightsApplicatorTest TESTNAME krita-image-KisFilterWeightsApplicatorTest ${kis_filter_weights_applicator_test_SRCS}) target_link_libraries(KisFilterWeightsApplicatorTest kritaimage Qt5::Test) ########### next target ############### set(kis_fill_interval_test_SRCS kis_fill_interval_test.cpp ) kde4_add_unit_test(KisFillIntervalTest TESTNAME krita-image-FillInterval-Test ${kis_fill_interval_test_SRCS}) target_link_libraries(KisFillIntervalTest kritaimage Qt5::Test) ########### next target ############### set(kis_fill_interval_map_test_SRCS kis_fill_interval_map_test.cpp ) kde4_add_unit_test(KisFillIntervalMapTest TESTNAME krita-image-FillIntervalMap-Test ${kis_fill_interval_map_test_SRCS}) target_link_libraries(KisFillIntervalMapTest kritaimage Qt5::Test) ########### next target ############### set(kis_scanline_fill_test_SRCS kis_scanline_fill_test.cpp ) kde4_add_unit_test(KisScanlineFillTest TESTNAME krita-image-ScanlineFill-Test ${kis_scanline_fill_test_SRCS}) target_link_libraries(KisScanlineFillTest kritaimage Qt5::Test) ########### next target ############### set(kis_keyframing_test_SRCS kis_keyframing_test.cpp ) kde4_add_unit_test(KisKeyframingTest TESTNAME krita-image-Keyframing-Test ${kis_keyframing_test_SRCS}) target_link_libraries(KisKeyframingTest ${KDE4_KDEUI_LIBS} kritaimage ${QT_QTTEST_LIBRARY}) ########### next target ############### set(kis_psd_layer_style_test_SRCS kis_psd_layer_style_test.cpp ) kde4_add_unit_test(KisPSDLayerStyleTest TESTNAME krita-image-PSDLayerStyle-Test ${kis_psd_layer_style_test_SRCS}) target_link_libraries(KisPSDLayerStyleTest kritaimage Qt5::Test) ########### next target ############### set(kis_dom_utils_test_SRCS kis_dom_utils_test.cpp ) kde4_add_unit_test(KisDomUtilsTest TESTNAME krita-image-DomUtils-Test ${kis_dom_utils_test_SRCS}) target_link_libraries(KisDomUtilsTest kritaimage Qt5::Test) ########### next target ############### set(kis_image_animation_interface_test_SRCS kis_image_animation_interface_test.cpp ) kde4_add_unit_test(KisImageAnimationInterfaceTest TESTNAME krita-image-ImageAnimationInterface-Test ${kis_image_animation_interface_test_SRCS}) target_link_libraries(KisImageAnimationInterfaceTest ${KDE4_KDEUI_LIBS} kritaimage ${QT_QTTEST_LIBRARY}) ########### next target ############### set(kis_onion_skin_compositor_test_SRCS kis_onion_skin_compositor_test.cpp ) kde4_add_unit_test(KisOnionSkinCompositorTest TESTNAME krita-image-OnionSkinCompositor-Test ${kis_onion_skin_compositor_test_SRCS}) target_link_libraries(KisOnionSkinCompositorTest ${KDE4_KDEUI_LIBS} kritaimage ${QT_QTTEST_LIBRARY}) ########### next target ############### set(kis_layer_styles_test_SRCS kis_layer_styles_test.cpp ) kde4_add_unit_test(KisLayerStylesTest TESTNAME krita-image-LayerStylesTest ${kis_layer_styles_test_SRCS}) target_link_libraries(KisLayerStylesTest kritaimage Qt5::Test) ########### next target ############### set(kis_layer_style_projection_plane_test_SRCS kis_layer_style_projection_plane_test.cpp ) kde4_add_unit_test(KisLayerStyleProjectionPlaneTest TESTNAME kritaimage-layer_style_projection_plane_test ${kis_layer_style_projection_plane_test_SRCS}) target_link_libraries(KisLayerStyleProjectionPlaneTest kritaimage Qt5::Test) ########### next target ############### set(kis_layer_style_filter_environment_test_SRCS kis_layer_style_filter_environment_test.cpp ) kde4_add_unit_test(KisLayerStyleFilterEnvironmentTest TESTNAME kritaimage-layer_style_filter_environment_test ${kis_layer_style_filter_environment_test_SRCS}) target_link_libraries(KisLayerStyleFilterEnvironmentTest ${KDE4_KDEUI_LIBS} kritaimage ${QT_QTTEST_LIBRARY}) ########### next target ############### set(kis_layer_style_filter_environment_test_SRCS kis_layer_style_filter_environment_test.cpp ) kde4_add_unit_test(KisLayerStyleFilterEnvironmentTest TESTNAME kritaimage-layer_style_filter_environment_test ${kis_layer_style_filter_environment_test_SRCS}) target_link_libraries(KisLayerStyleFilterEnvironmentTest ${KDE4_KDEUI_LIBS} kritaimage ${QT_QTTEST_LIBRARY}) ########### next target ############### set(kis_projection_leaf_test_SRCS kis_projection_leaf_test.cpp ) kde4_add_unit_test(KisProjectionLeafTest TESTNAME kritaimage-projection_leaf_test ${kis_projection_leaf_test_SRCS}) target_link_libraries(KisProjectionLeafTest kritaimage ${QT_QTTEST_LIBRARY}) ########### next target ############### set(kis_lod_capable_layer_offset_test_SRCS kis_lod_capable_layer_offset_test.cpp ) kde4_add_unit_test(KisLodCapableLayerOffsetTest TESTNAME kritaimage-lod_capable_layer_offset_test ${kis_lod_capable_layer_offset_test_SRCS}) target_link_libraries(KisLodCapableLayerOffsetTest kritaimage ${QT_QTTEST_LIBRARY}) diff --git a/krita/image/tests/kis_basic_math_toolbox_test.cpp b/krita/image/tests/kis_basic_math_toolbox_test.cpp deleted file mode 100644 index ecaadc1d44..0000000000 --- a/krita/image/tests/kis_basic_math_toolbox_test.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2007 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_basic_math_toolbox_test.h" - -#include -#include "kis_basic_math_toolbox.h" - -void KisBasicMathToolboxTest::testCreation() -{ - KisBasicMathToolbox test; -} - - -QTEST_MAIN(KisBasicMathToolboxTest) diff --git a/krita/image/tests/kis_basic_math_toolbox_test.h b/krita/image/tests/kis_basic_math_toolbox_test.h deleted file mode 100644 index f1cabc26d4..0000000000 --- a/krita/image/tests/kis_basic_math_toolbox_test.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2007 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_BASIC_MATH_TOOLBOX_TEST_H -#define KIS_BASIC_MATH_TOOLBOX_TEST_H - -#include - -class KisBasicMathToolboxTest : public QObject -{ - Q_OBJECT -private Q_SLOTS: - - void testCreation(); - -}; - -#endif diff --git a/krita/image/tests/kis_math_toolbox_test.cpp b/krita/image/tests/kis_math_toolbox_test.cpp index ca70a24c29..41a4daa6a7 100644 --- a/krita/image/tests/kis_math_toolbox_test.cpp +++ b/krita/image/tests/kis_math_toolbox_test.cpp @@ -1,37 +1,30 @@ /* * Copyright (c) 2007 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_math_toolbox_test.h" #include -#include -#include #include "kis_math_toolbox.h" void KisMathToolboxTest::testCreation() { - KisMathToolboxRegistry * reg = KisMathToolboxRegistry::instance(); - QVERIFY(reg); - - const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); - KisMathToolbox * toolbox = reg->get(cs->mathToolboxId().id()); - QVERIFY(toolbox); + KisMathToolbox tb; } QTEST_MAIN(KisMathToolboxTest) diff --git a/krita/plugins/filters/imageenhancement/kis_wavelet_noise_reduction.cpp b/krita/plugins/filters/imageenhancement/kis_wavelet_noise_reduction.cpp index 70708f9cbe..86aa5208dc 100644 --- a/krita/plugins/filters/imageenhancement/kis_wavelet_noise_reduction.cpp +++ b/krita/plugins/filters/imageenhancement/kis_wavelet_noise_reduction.cpp @@ -1,133 +1,129 @@ /* * 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 #include #include KisWaveletNoiseReduction::KisWaveletNoiseReduction() : KisFilter(id(), categoryEnhance(), i18n("&Wavelet Noise Reducer...")) { setSupportsPainting(false); setSupportsThreading(false); } KisWaveletNoiseReduction::~KisWaveletNoiseReduction() { } KisConfigWidget * KisWaveletNoiseReduction::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP) const { vKisDoubleWidgetParam param; param.push_back(KisDoubleWidgetParam(0.0, 256.0, BEST_WAVELET_THRESHOLD_VALUE, i18n("Threshold"), "threshold")); return new KisMultiDoubleFilterWidget(id().id(), parent, id().id(), param); } KisFilterConfiguration* KisWaveletNoiseReduction::factoryConfiguration(const KisPaintDeviceSP) const { KisFilterConfiguration* config = new KisFilterConfiguration(id().id(), 0); config->setProperty("threshold", BEST_WAVELET_THRESHOLD_VALUE); return config; } void KisWaveletNoiseReduction::processImpl(KisPaintDeviceSP device, const QRect& applyRect, const KisFilterConfiguration* config, KoUpdater* progressUpdater ) const { Q_ASSERT(device); // TODO take selections into account float threshold; if (!config) { config = defaultConfiguration(device); } threshold = config->getDouble("threshold", BEST_WAVELET_THRESHOLD_VALUE); qint32 depth = device->colorSpace()->colorChannelCount(); int size; int maxrectsize = qMax(applyRect.width(), applyRect.height()); for (size = 2; size < maxrectsize; size *= 2) ; - KisMathToolbox* mathToolbox = KisMathToolboxRegistry::instance()->get(device->colorSpace()->mathToolboxId().id()); + KisMathToolbox mathToolbox; if (progressUpdater) { - progressUpdater->setRange(0, mathToolbox->fastWaveletTotalSteps(applyRect) * 2 + size*size*depth); + progressUpdater->setRange(0, mathToolbox.fastWaveletTotalSteps(applyRect) * 2 + size*size*depth); } int count = 0; -// connect(mathToolbox, SIGNAL(nextStep()), this, SLOT(incProgress())); - // dbgFilters << size <<"" << maxrectsize <<"" << srcTopLeft.x() <<"" << srcTopLeft.y(); // dbgFilters <<"Transforming..."; -// setProgressStage( i18n("Fast wavelet transformation") ,progress()); KisMathToolbox::KisWavelet* buff = 0; KisMathToolbox::KisWavelet* wav = 0; try { - buff = mathToolbox->initWavelet(device, applyRect); + buff = mathToolbox.initWavelet(device, applyRect); } catch (std::bad_alloc) { if (buff) delete buff; return; } try { - wav = mathToolbox->fastWaveletTransformation(device, applyRect, buff); + wav = mathToolbox.fastWaveletTransformation(device, applyRect, buff); } catch (std::bad_alloc) { if (wav) delete wav; return; } // dbgFilters <<"Thresholding..."; float* fin = wav->coeffs + wav->depth * wav->size * wav->size; for (float* it = wav->coeffs + wav->depth; it < fin; it++) { if (*it > threshold) { *it -= threshold; } else if (*it < -threshold) { *it += threshold; } else { *it = 0.; } if (progressUpdater) progressUpdater->setValue(++count); } // dbgFilters <<"Untransforming..."; - mathToolbox->fastWaveletUntransformation(device, applyRect, wav, buff); + mathToolbox.fastWaveletUntransformation(device, applyRect, wav, buff); delete wav; delete buff; -// disconnect(mathToolbox, SIGNAL(nextStep()), this, SLOT(incProgress())); } diff --git a/krita/plugins/filters/phongbumpmap/kis_phong_bumpmap_filter.cpp b/krita/plugins/filters/phongbumpmap/kis_phong_bumpmap_filter.cpp index 4c44f2744d..5d5c28fb22 100644 --- a/krita/plugins/filters/phongbumpmap/kis_phong_bumpmap_filter.cpp +++ b/krita/plugins/filters/phongbumpmap/kis_phong_bumpmap_filter.cpp @@ -1,238 +1,238 @@ /* * Copyright (c) 2010-2011 José Luis Vergara * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * 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_phong_bumpmap_filter.h" #include "kis_phong_bumpmap_config_widget.h" #include "phong_pixel_processor.h" #include "kis_debug.h" #include "kis_paint_device.h" #include "kis_config_widget.h" #include "KoUpdater.h" #include "kis_math_toolbox.h" #include "KoColorSpaceRegistry.h" #include #include #include "kis_iterator_ng.h" #include "kundo2command.h" #include "kis_painter.h" KisFilterPhongBumpmap::KisFilterPhongBumpmap() : KisFilter(KoID("phongbumpmap" , i18n("PhongBumpmap")), KisFilter::categoryMap(), i18n("&PhongBumpmap...")) { setColorSpaceIndependence(TO_LAB16); setSupportsPainting(true); setSupportsLevelOfDetail(true); } void KisFilterPhongBumpmap::processImpl(KisPaintDeviceSP device, const QRect& applyRect, const KisFilterConfiguration *config, KoUpdater *progressUpdater ) const { if (!config) return; if (progressUpdater) progressUpdater->setProgress(0); QString userChosenHeightChannel = config->getString(PHONG_HEIGHT_CHANNEL, "FAIL"); bool m_usenormalmap = config->getBool(USE_NORMALMAP_IS_ENABLED); if (userChosenHeightChannel == "FAIL") { qDebug("FIX YOUR FILTER"); return; } KoChannelInfo *m_heightChannel = 0; Q_FOREACH (KoChannelInfo* channel, device->colorSpace()->channels()) { if (userChosenHeightChannel == channel->name()) { m_heightChannel = channel; } } if (!m_heightChannel) { m_heightChannel = device->colorSpace()->channels().first(); } KIS_ASSERT_RECOVER_RETURN(m_heightChannel); QRect inputArea = applyRect; QRect outputArea = applyRect; if (m_usenormalmap==false) { inputArea.adjust(-1, -1, 1, 1); } quint32 posup; quint32 posdown; quint32 posleft; quint32 posright; QColor I; //Reflected light if (progressUpdater) progressUpdater->setProgress(1); //======Preparation paraphlenalia======= //Hardcoded facts about Phong Bumpmap: it _will_ generate an RGBA16 bumpmap const quint8 BYTE_DEPTH_OF_BUMPMAP = 2; // 16 bits per channel const quint8 CHANNEL_COUNT_OF_BUMPMAP = 4; // RGBA const quint32 pixelsOfInputArea = abs(inputArea.width() * inputArea.height()); const quint32 pixelsOfOutputArea = abs(outputArea.width() * outputArea.height()); const quint8 pixelSize = BYTE_DEPTH_OF_BUMPMAP * CHANNEL_COUNT_OF_BUMPMAP; const quint32 bytesToFillBumpmapArea = pixelsOfOutputArea * pixelSize; QVector bumpmap(bytesToFillBumpmapArea); quint8 *bumpmapDataPointer = bumpmap.data(); quint32 ki = KoChannelInfo::displayPositionToChannelIndex(m_heightChannel->displayPosition(), device->colorSpace()->channels()); PhongPixelProcessor tileRenderer(pixelsOfInputArea, config); if (progressUpdater) progressUpdater->setProgress(2); //===============RENDER================= QVector toDoubleFuncPtr(device->colorSpace()->channels().count()); - KisMathToolbox *mathToolbox = KisMathToolboxRegistry::instance()->value(device->colorSpace()->mathToolboxId().id()); - if (!mathToolbox->getToDoubleChannelPtr(device->colorSpace()->channels(), toDoubleFuncPtr)) { + KisMathToolbox mathToolbox; + if (!mathToolbox.getToDoubleChannelPtr(device->colorSpace()->channels(), toDoubleFuncPtr)) { return; } KisHLineConstIteratorSP iterator; quint32 curPixel = 0; iterator = device->createHLineConstIteratorNG(inputArea.x(), inputArea.y(), inputArea.width() ); if (m_usenormalmap==false) { for (qint32 srcRow = 0; srcRow < inputArea.height(); ++srcRow) { do { const quint8 *data = iterator->oldRawData(); tileRenderer.realheightmap[curPixel] = toDoubleFuncPtr[ki](data, device->colorSpace()->channels()[ki]->pos()); curPixel++; } while (iterator->nextPixel()); iterator->nextRow(); } if (progressUpdater) progressUpdater->setProgress(50); const int tileHeightMinus1 = inputArea.height() - 1; const int tileWidthMinus1 = inputArea.width() - 1; // Foreach INNER pixel in tile for (int y = 1; y < tileHeightMinus1; ++y) { for (int x = 1; x < tileWidthMinus1; ++x) { posup = (y + 1) * inputArea.width() + x; posdown = (y - 1) * inputArea.width() + x; posleft = y * inputArea.width() + x - 1; posright = y * inputArea.width() + x + 1; memcpy(bumpmapDataPointer, tileRenderer.IlluminatePixelFromHeightmap(posup, posdown, posleft, posright).data(), pixelSize); bumpmapDataPointer += pixelSize; } } } else { for (qint32 srcRow = 0; srcRow < inputArea.height(); ++srcRow) { do { const quint8 *data = iterator->oldRawData(); tileRenderer.realheightmap[curPixel] = toDoubleFuncPtr[ki](data, device->colorSpace()->channels()[ki]->pos()); QVector current_pixel_values(4); device->colorSpace()->normalisedChannelsValue(data, current_pixel_values ); //dbgKrita<< "Vector:" << current_pixel_values[2] << "," << current_pixel_values[1] << "," << current_pixel_values[0]; memcpy(bumpmapDataPointer, tileRenderer.IlluminatePixelFromNormalmap(current_pixel_values[2], current_pixel_values[1], current_pixel_values[0]).data(), pixelSize); curPixel++; //pointer that crashes here, but not in the other if statement. bumpmapDataPointer += pixelSize; } while (iterator->nextPixel()); iterator->nextRow(); } } if (progressUpdater) progressUpdater->setProgress(90); KisPaintDeviceSP bumpmapPaintDevice = new KisPaintDevice(KoColorSpaceRegistry::instance()->rgb16()); bumpmapPaintDevice->writeBytes(bumpmap.data(), outputArea.x(), outputArea.y(), outputArea.width(), outputArea.height()); KUndo2Command *leaker = bumpmapPaintDevice->convertTo(device->colorSpace(), KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); KisPainter copier(device); copier.bitBlt(outputArea.x(), outputArea.y(), bumpmapPaintDevice, outputArea.x(), outputArea.y(), outputArea.width(), outputArea.height()); //device->prepareClone(bumpmapPaintDevice); //device->makeCloneFrom(bumpmapPaintDevice, bumpmapPaintDevice->extent()); // THIS COULD BE BUG GY delete leaker; if (progressUpdater) progressUpdater->setProgress(100); } KisFilterConfiguration *KisFilterPhongBumpmap::factoryConfiguration(const KisPaintDeviceSP) const { KisFilterConfiguration *config = new KisFilterConfiguration(id(), 2); config->setProperty(PHONG_AMBIENT_REFLECTIVITY, 0.2); config->setProperty(PHONG_DIFFUSE_REFLECTIVITY, 0.5); config->setProperty(PHONG_SPECULAR_REFLECTIVITY, 0.3); config->setProperty(PHONG_SHINYNESS_EXPONENT, 2); config->setProperty(USE_NORMALMAP_IS_ENABLED, false); config->setProperty(PHONG_DIFFUSE_REFLECTIVITY_IS_ENABLED, true); config->setProperty(PHONG_SPECULAR_REFLECTIVITY_IS_ENABLED, true); // Indexes are off by 1 simply because arrays start at 0 and the GUI naming scheme started at 1 config->setProperty(PHONG_ILLUMINANT_IS_ENABLED[0], true); config->setProperty(PHONG_ILLUMINANT_IS_ENABLED[1], true); config->setProperty(PHONG_ILLUMINANT_IS_ENABLED[2], false); config->setProperty(PHONG_ILLUMINANT_IS_ENABLED[3], false); config->setProperty(PHONG_ILLUMINANT_COLOR[0], QColor(255, 255, 0)); config->setProperty(PHONG_ILLUMINANT_COLOR[1], QColor(255, 0, 0)); config->setProperty(PHONG_ILLUMINANT_COLOR[2], QColor(0, 0, 255)); config->setProperty(PHONG_ILLUMINANT_COLOR[3], QColor(0, 255, 0)); config->setProperty(PHONG_ILLUMINANT_AZIMUTH[0], 50); config->setProperty(PHONG_ILLUMINANT_AZIMUTH[1], 100); config->setProperty(PHONG_ILLUMINANT_AZIMUTH[2], 150); config->setProperty(PHONG_ILLUMINANT_AZIMUTH[3], 200); config->setProperty(PHONG_ILLUMINANT_INCLINATION[0], 25); config->setProperty(PHONG_ILLUMINANT_INCLINATION[1], 20); config->setProperty(PHONG_ILLUMINANT_INCLINATION[2], 30); config->setProperty(PHONG_ILLUMINANT_INCLINATION[3], 40); return config; } QRect KisFilterPhongBumpmap::neededRect(const QRect &rect, const KisFilterConfiguration* /*config*/, int /*lod*/) const { return rect.adjusted(-1, -1, 1, 1); } QRect KisFilterPhongBumpmap::changedRect(const QRect &rect, const KisFilterConfiguration* /*config*/, int /*lod*/) const { return rect; } KisConfigWidget *KisFilterPhongBumpmap::createConfigurationWidget(QWidget *parent, const KisPaintDeviceSP dev) const { KisPhongBumpmapConfigWidget *w = new KisPhongBumpmapConfigWidget(dev, parent); return w; } diff --git a/krita/plugins/filters/phongbumpmap/phong_pixel_processor.cpp b/krita/plugins/filters/phongbumpmap/phong_pixel_processor.cpp index 738f681409..b2e4d0d50b 100644 --- a/krita/plugins/filters/phongbumpmap/phong_pixel_processor.cpp +++ b/krita/plugins/filters/phongbumpmap/phong_pixel_processor.cpp @@ -1,203 +1,202 @@ /* * Copyright (c) 2010-2012 José Luis Vergara * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "phong_pixel_processor.h" #include -#include "kis_math_toolbox.h" #include #include PhongPixelProcessor::PhongPixelProcessor(quint32 pixelArea, const KisPropertiesConfiguration* config) { m_pixelArea = pixelArea; initialize(config); } void PhongPixelProcessor::initialize(const KisPropertiesConfiguration* config) { // Basic, fundamental normal_vector = QVector3D(0, 0, 1); vision_vector = QVector3D(0, 0, 1); x_vector = QVector3D(1, 0, 0); y_vector = QVector3D(0, 1, 0); // Mutable light_vector = QVector3D(0, 0, 0); reflection_vector = QVector3D(0, 0, 0); //setLightVector(QVector3D(-8, 8, 2)); Illuminant light[PHONG_TOTAL_ILLUMINANTS]; QVariant guiLight[PHONG_TOTAL_ILLUMINANTS]; qint32 azimuth; qint32 inclination; for (int i = 0; i < PHONG_TOTAL_ILLUMINANTS; i++) { if (config->getBool(PHONG_ILLUMINANT_IS_ENABLED[i])) { config->getProperty(PHONG_ILLUMINANT_COLOR[i], guiLight[i]); light[i].RGBvalue << guiLight[i].value().redF(); light[i].RGBvalue << guiLight[i].value().greenF(); light[i].RGBvalue << guiLight[i].value().blueF(); azimuth = config->getInt(PHONG_ILLUMINANT_AZIMUTH[i]) - 90; inclination = config->getInt(PHONG_ILLUMINANT_INCLINATION[i]); qreal m; //2D vector magnitude light[i].lightVector.setZ( sin( inclination * M_PI / 180 ) ); m = cos( inclination * M_PI / 180); light[i].lightVector.setX( cos( azimuth * M_PI / 180 ) * m ); light[i].lightVector.setY( sin( azimuth * M_PI / 180 ) * m ); //Pay close attention to this, indexes will move in this line lightSources.append(light[i]); } } size = lightSources.size(); //Code that exists only to swiftly switch to the other algorithm (reallyFastIlluminatePixel) to test if (size > 0) { fastLight = light[0]; fastLight2 = light[0]; } //Ka, Kd and Ks must be between 0 and 1 or grave errors will happen Ka = config->getDouble(PHONG_AMBIENT_REFLECTIVITY); Kd = config->getDouble(PHONG_DIFFUSE_REFLECTIVITY); Ks = config->getDouble(PHONG_SPECULAR_REFLECTIVITY); shiny_exp = config->getInt(PHONG_SHINYNESS_EXPONENT); Ia = Id = Is = 0; diffuseLightIsEnabled = config->getBool(PHONG_DIFFUSE_REFLECTIVITY_IS_ENABLED); specularLightIsEnabled = config->getBool(PHONG_SPECULAR_REFLECTIVITY_IS_ENABLED); realheightmap = QVector(m_pixelArea, 0); } PhongPixelProcessor::~PhongPixelProcessor() { } void PhongPixelProcessor::setLightVector(QVector3D lightVector) { lightVector.normalize(); light_vector = lightVector; } QVector PhongPixelProcessor::IlluminatePixelFromHeightmap(quint32 posup, quint32 posdown, quint32 posleft, quint32 posright) { QVector finalPixel(4, 0xFFFF); if (lightSources.size() == 0) return finalPixel; // Algorithm begins, Phong Illumination Model normal_vector.setX(- realheightmap[posright] + realheightmap[posleft]); normal_vector.setY(- realheightmap[posup] + realheightmap[posdown]); normal_vector.setZ(8); normal_vector.normalize(); // PREPARE ALGORITHM HERE finalPixel = IlluminatePixel(); return finalPixel; } QVector PhongPixelProcessor::IlluminatePixel() { qreal temp; quint8 channel = 0; const quint8 totalChannels = 3; // The 4th is alpha and we'll fill it with a nice 0xFFFF qreal computation[] = {0, 0, 0}; QVector finalPixel(4, 0xFFFF); if (lightSources.size() == 0) return finalPixel; // PREPARE ALGORITHM HERE for (int i = 0; i < size; i++) { light_vector = lightSources.at(i).lightVector; for (channel = 0; channel < totalChannels; channel++) { Ia = lightSources.at(i).RGBvalue.at(channel) * Ka; computation[channel] += Ia; } if (diffuseLightIsEnabled) { temp = Kd * QVector3D::dotProduct(normal_vector, light_vector); for (channel = 0; channel < totalChannels; channel++) { Id = lightSources.at(i).RGBvalue.at(channel) * temp; if (Id < 0) Id = 0; if (Id > 1) Id = 1; computation[channel] += Id; } } if (specularLightIsEnabled) { reflection_vector = (2 * pow(QVector3D::dotProduct(normal_vector, light_vector), shiny_exp)) * normal_vector - light_vector; temp = Ks * QVector3D::dotProduct(vision_vector, reflection_vector); for (channel = 0; channel < totalChannels; channel++) { Is = lightSources.at(i).RGBvalue.at(channel) * temp; if (Is < 0) Is = 0; if (Is > 1) Is = 1; computation[channel] += Is; } } } for (channel = 0; channel < totalChannels; channel++) { if (computation[channel] > 1) computation[channel] = 1; if (computation[channel] < 0) computation[channel] = 0; } //RGBA actually uses the BGRA order of channels, hence the disorder finalPixel[2] = quint16(computation[0] * 0xFFFF); finalPixel[1] = quint16(computation[1] * 0xFFFF); finalPixel[0] = quint16(computation[2] * 0xFFFF); return finalPixel; } QVector PhongPixelProcessor::IlluminatePixelFromNormalmap(qreal r, qreal g, qreal b) { QVector finalPixel(4, 0xFFFF); if (lightSources.size() == 0) return finalPixel; // if () // Algorithm begins, Phong Illumination Model normal_vector.setX(r*2-1.0); normal_vector.setY(-(g*2-1.0)); normal_vector.setZ(b*2-1.0); //normal_vector.normalize(); // PREPARE ALGORITHM HERE finalPixel = IlluminatePixel(); return finalPixel; } diff --git a/krita/plugins/filters/tests/kis_all_filter_test.cpp b/krita/plugins/filters/tests/kis_all_filter_test.cpp index c34dd416d5..0b8daec95a 100644 --- a/krita/plugins/filters/tests/kis_all_filter_test.cpp +++ b/krita/plugins/filters/tests/kis_all_filter_test.cpp @@ -1,316 +1,316 @@ /* * Copyright (c) 2008 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * 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_all_filter_test.h" #include #include "filter/kis_filter_configuration.h" #include "filter/kis_filter_registry.h" #include "kis_selection.h" #include "kis_processing_information.h" #include "filter/kis_filter.h" #include "kis_pixel_selection.h" #include "kis_transaction.h" #include bool compareQImages(QPoint & pt, const QImage & image1, const QImage & image2) { // QTime t; // t.start(); int w1 = image1.width(); int h1 = image1.height(); int w2 = image2.width(); int h2 = image2.height(); if (w1 != w2 || h1 != h2) { dbgKrita << w1 << " " << w2 << " " << h1 << " " << h2; pt.setX(-1); pt.setY(-1); return false; } for (int x = 0; x < w1; ++x) { for (int y = 0; y < h1; ++y) { if (image1.pixel(x, y) != image2.pixel(x, y)) { pt.setX(x); pt.setY(y); return false; } } } // dbgKrita << "compareQImages time elapsed:" << t.elapsed(); return true; } bool testFilterSrcNotIsDev(KisFilterSP f) { const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); QImage qimage(QString(FILES_DATA_DIR) + QDir::separator() + "lena.png"); QImage result(QString(FILES_DATA_DIR) + QDir::separator() + "lena_" + f->id() + ".png"); KisPaintDeviceSP dev = new KisPaintDevice(cs); KisPaintDeviceSP dstdev = new KisPaintDevice(cs); dev->convertFromQImage(qimage, 0, 0, 0); // Get the predefined configuration from a file KisFilterConfiguration * kfc = f->defaultConfiguration(dev); QFile file(QString(FILES_DATA_DIR) + QDir::separator() + f->id() + ".cfg"); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { //dbgKrita << "creating new file for " << f->id(); file.open(QIODevice::WriteOnly | QIODevice::Text); QTextStream out(&file); out.setCodec("UTF-8"); out << kfc->toXML(); } else { QString s; QTextStream in(&file); - out.setCodec("UTF-8"); + in.setCodec("UTF-8"); s = in.readAll(); //dbgKrita << "Read for " << f->id() << "\n" << s; kfc->fromXML(s); } dbgKrita << f->id();// << "\n" << kfc->toXML() << "\n"; f->process(dev, dstdev, 0, QRect(QPoint(0,0), qimage.size()), kfc); QPoint errpoint; if (!compareQImages(errpoint, result, dstdev->convertToQImage(0, 0, 0, qimage.width(), qimage.height()))) { dev->convertToQImage(0, 0, 0, qimage.width(), qimage.height()).save(QString("src_not_is_dst_lena_%1.png").arg(f->id())); return false; } return true; } bool testFilterNoTransaction(KisFilterSP f) { const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); QImage qimage(QString(FILES_DATA_DIR) + QDir::separator() + "lena.png"); QImage result(QString(FILES_DATA_DIR) + QDir::separator() + "lena_" + f->id() + ".png"); KisPaintDeviceSP dev = new KisPaintDevice(cs); dev->convertFromQImage(qimage, 0, 0, 0); // Get the predefined configuration from a file KisFilterConfiguration * kfc = f->defaultConfiguration(dev); QFile file(QString(FILES_DATA_DIR) + QDir::separator() + f->id() + ".cfg"); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { //dbgKrita << "creating new file for " << f->id(); file.open(QIODevice::WriteOnly | QIODevice::Text); QTextStream out(&file); out.setCodec("UTF-8"); out << kfc->toXML(); } else { QString s; QTextStream in(&file); in.setCodec("UTF-8"); s = in.readAll(); //dbgKrita << "Read for " << f->id() << "\n" << s; kfc->fromXML(s); } dbgKrita << f->id();// << "\n" << kfc->toXML() << "\n"; f->process(dev, QRect(QPoint(0,0), qimage.size()), kfc); QPoint errpoint; if (!compareQImages(errpoint, result, dev->convertToQImage(0, 0, 0, qimage.width(), qimage.height()))) { dev->convertToQImage(0, 0, 0, qimage.width(), qimage.height()).save(QString("no_transactio_lena_%1.png").arg(f->id())); return false; } return true; } bool testFilter(KisFilterSP f) { const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); QImage qimage(QString(FILES_DATA_DIR) + QDir::separator() + "lena.png"); QString resultFileName = QString(FILES_DATA_DIR) + QDir::separator() + "lena_" + f->id() + ".png"; QImage result(resultFileName); if (!QFileInfo(resultFileName).exists()) { dbgKrita << resultFileName << " not found"; return false; } KisPaintDeviceSP dev = new KisPaintDevice(cs); dev->convertFromQImage(qimage, 0, 0, 0); KisTransaction * cmd = new KisTransaction(kundo2_noi18n(f->name()), dev); // Get the predefined configuration from a file KisFilterConfiguration * kfc = f->defaultConfiguration(dev); QFile file(QString(FILES_DATA_DIR) + QDir::separator() + f->id() + ".cfg"); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { //dbgKrita << "creating new file for " << f->id(); file.open(QIODevice::WriteOnly | QIODevice::Text); QTextStream out(&file); out.setCodec("UTF-8"); out << kfc->toXML(); } else { QString s; QTextStream in(&file); in.setCodec("UTF-8"); s = in.readAll(); //dbgKrita << "Read for " << f->id() << "\n" << s; kfc->fromXML(s); } dbgKrita << f->id();// << "\n" << kfc->toXML() << "\n"; f->process(dev, QRect(QPoint(0,0), qimage.size()), kfc); QPoint errpoint; delete cmd; if (!compareQImages(errpoint, result, dev->convertToQImage(0, 0, 0, qimage.width(), qimage.height()))) { dbgKrita << errpoint; dev->convertToQImage(0, 0, 0, qimage.width(), qimage.height()).save(QString("lena_%1.png").arg(f->id())); return false; } return true; } bool testFilterWithSelections(KisFilterSP f) { const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); QImage qimage(QString(FILES_DATA_DIR) + QDir::separator() + "lena.png"); QImage result(QString(FILES_DATA_DIR) + QDir::separator() + "lena_" + f->id() + ".png"); KisPaintDeviceSP dev = new KisPaintDevice(cs); dev->convertFromQImage(qimage, 0, 0, 0); // Get the predefined configuration from a file KisFilterConfiguration * kfc = f->defaultConfiguration(dev); QFile file(QString(FILES_DATA_DIR) + QDir::separator() + f->id() + ".cfg"); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { //dbgKrita << "creating new file for " << f->id(); file.open(QIODevice::WriteOnly | QIODevice::Text); QTextStream out(&file); out.setCodec("UTF-8"); out << kfc->toXML(); } else { QString s; QTextStream in(&file); in.setCodec("UTF-8"); s = in.readAll(); //dbgKrita << "Read for " << f->id() << "\n" << s; kfc->fromXML(s); } dbgKrita << f->id();// << "\n"; << kfc->toXML() << "\n"; KisSelectionSP sel1 = new KisSelection(new KisSelectionDefaultBounds(dev)); sel1->pixelSelection()->select(qimage.rect()); f->process(dev, dev, sel1, QRect(QPoint(0,0), qimage.size()), kfc); QPoint errpoint; if (!compareQImages(errpoint, result, dev->convertToQImage(0, 0, 0, qimage.width(), qimage.height()))) { dev->convertToQImage(0, 0, 0, qimage.width(), qimage.height()).save(QString("sel_lena_%1.png").arg(f->id())); return false; } return true; } void KisAllFilterTest::testAllFilters() { QStringList failures; QStringList successes; QList filterList = KisFilterRegistry::instance()->keys(); qSort(filterList); for (QList::Iterator it = filterList.begin(); it != filterList.end(); ++it) { if (testFilter(KisFilterRegistry::instance()->value(*it))) successes << *it; else failures << *it; } dbgKrita << "Success: " << successes; if (failures.size() > 0) { QFAIL(QString("Failed filters:\n\t %1").arg(failures.join("\n\t")).toLatin1()); } } void KisAllFilterTest::testAllFiltersNoTransaction() { QStringList failures; QStringList successes; QList filterList = KisFilterRegistry::instance()->keys(); qSort(filterList); for (QList::Iterator it = filterList.begin(); it != filterList.end(); ++it) { if (testFilterNoTransaction(KisFilterRegistry::instance()->value(*it))) successes << *it; else failures << *it; } dbgKrita << "Success (no transaction): " << successes; if (failures.size() > 0) { QFAIL(QString("Failed filters (no transaction):\n\t %1").arg(failures.join("\n\t")).toLatin1()); } } void KisAllFilterTest::testAllFiltersSrcNotIsDev() { QStringList failures; QStringList successes; QList filterList = KisFilterRegistry::instance()->keys(); qSort(filterList); for (QList::Iterator it = filterList.begin(); it != filterList.end(); ++it) { if (testFilterSrcNotIsDev(KisFilterRegistry::instance()->value(*it))) successes << *it; else failures << *it; } dbgKrita << "Src!=Dev Success: " << successes; if (failures.size() > 0) { QFAIL(QString("Src!=Dev Failed filters:\n\t %1").arg(failures.join("\n\t")).toLatin1()); } } void KisAllFilterTest::testAllFiltersWithSelections() { QStringList failures; QStringList successes; QList filterList = KisFilterRegistry::instance()->keys(); qSort(filterList); for (QList::Iterator it = filterList.begin(); it != filterList.end(); ++it) { if (testFilterWithSelections(KisFilterRegistry::instance()->value(*it))) successes << *it; else failures << *it; } dbgKrita << "Success: " << successes; if (failures.size() > 0) { QFAIL(QString("Failed filters with selections:\n\t %1").arg(failures.join("\n\t")).toLatin1()); } } QTEST_MAIN(KisAllFilterTest) diff --git a/libs/pigment/KoColorSpace.h b/libs/pigment/KoColorSpace.h index 31003b8052..2968000018 100644 --- a/libs/pigment/KoColorSpace.h +++ b/libs/pigment/KoColorSpace.h @@ -1,585 +1,580 @@ /* * Copyright (c) 2005 Boudewijn Rempt * Copyright (c) 2006-2007 Cyrille Berger * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 KOCOLORSPACE_H #define KOCOLORSPACE_H #include #include #include #include #include #include "KoColorSpaceConstants.h" #include "KoColorConversionTransformation.h" #include "KoCompositeOp.h" #include #include "kritapigment_export.h" class QDomDocument; class QDomElement; class KoChannelInfo; class KoColorProfile; class KoColorTransformation; class QBitArray; enum Deletability { OwnedByRegistryDoNotDelete, OwnedByRegistryRegistryDeletes, NotOwnedByRegistry }; enum ColorSpaceIndependence { FULLY_INDEPENDENT, TO_LAB16, TO_RGBA8, TO_RGBA16 }; class KoMixColorsOp; class KoConvolutionOp; /** * A KoColorSpace is the definition of a certain color space. * * A color model and a color space are two related concepts. A color * model is more general in that it describes the channels involved and * how they in broad terms combine to describe a color. Examples are * RGB, HSV, CMYK. * * A color space is more specific in that it also describes exactly how * the channels are combined. So for each color model there can be a * number of specific color spaces. So RGB is the model and sRGB, * adobeRGB, etc are colorspaces. * * In Pigment KoColorSpace acts as both a color model and a color space. * You can think of the class definition as the color model, but the * instance of the class as representing a colorspace. * * A third concept is the profile represented by KoColorProfile. It * represents the info needed to specialize a color model into a color * space. * * KoColorSpace is an abstract class serving as an interface. * * Subclasses implement actual color spaces * Some subclasses implement only some parts and are named Traits * */ class KRITAPIGMENT_EXPORT KoColorSpace { friend class KoColorSpaceRegistry; friend class KoColorSpaceFactory; protected: /// Only for use by classes that serve as baseclass for real color spaces KoColorSpace(); public: /// Should be called by real color spaces KoColorSpace(const QString &id, const QString &name, KoMixColorsOp* mixColorsOp, KoConvolutionOp* convolutionOp); virtual bool operator==(const KoColorSpace& rhs) const; protected: virtual ~KoColorSpace(); public: //========== Channels =====================================================// /// Return a list describing all the channels this color model has. The order /// of the channels in the list is the order of channels in the pixel. To find /// out the preferred display position, use KoChannelInfo::displayPosition. virtual QList channels() const; /** * The total number of channels for a single pixel in this color model */ virtual quint32 channelCount() const = 0; /** * The total number of color channels (excludes alpha) for a single * pixel in this color model. */ virtual quint32 colorChannelCount() const = 0; /** * returns a QBitArray that contains true for the specified * channel types: * * @param color if true, set all color channels to true * @param alpha if true, set all alpha channels to true * * The order of channels is the colorspace descriptive order, * not the pixel order. */ QBitArray channelFlags(bool color = true, bool alpha = false) const; /** * The size in bytes of a single pixel in this color model */ virtual quint32 pixelSize() const = 0; /** * Return a string with the channel's value suitable for display in the gui. */ virtual QString channelValueText(const quint8 *pixel, quint32 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 quint8 *pixel, quint32 channelIndex) const = 0; /** * Return a QVector of floats with channels' values normalized * to floating point range 0 to 1. */ virtual void normalisedChannelsValue(const quint8 *pixel, QVector &channels) const = 0; /** * Write in the pixel the value from the normalized vector. */ virtual void fromNormalisedChannelsValue(quint8 *pixel, const QVector &values) 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 quint8 scaleToU8(const quint8 * srcPixel, qint32 channelPos) const = 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 color space, * with the intent being that the pixel should look like it only has the given channel. */ virtual void singleChannelPixel(quint8 *dstPixel, const quint8 *srcPixel, quint32 channelIndex) const = 0; //========== Identification ===============================================// /** * ID for use in files and internally: unchanging name. As the id must be unique * it is usually the concatenation of the id of the color model and of the color * depth, for instance "RGBA8" or "CMYKA16" or "XYZA32f". */ virtual QString id() const; /** * User visible name which contains the name of the color model and of the color depth. * For intance "RGBA (8-bits)" or "CMYKA (16-bits)". */ virtual QString name() const; /** * @return a string that identify the color model (for instance "RGB" or "CMYK" ...) * @see KoColorModelStandardIds.h */ virtual KoID colorModelId() const = 0; /** * @return a string that identify the bit depth (for instance "U8" or "F16" ...) * @see KoColorModelStandardIds.h */ virtual KoID colorDepthId() const = 0; /** * @return true if the profile given in argument can be used by this color space */ virtual bool profileIsCompatible(const KoColorProfile* profile) const = 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) const = 0; //========== Capabilities =================================================// /** * Tests if the colorspace offers the specific composite op. */ virtual bool hasCompositeOp(const QString & id) const; /** * Returns the list of user-visible composite ops supported by this colorspace. */ virtual QList compositeOps() const; /** * Retrieve a single composite op from the ones this colorspace offers. * If the requeste composite op does not exist, COMPOSITE_OVER is returned. */ virtual const KoCompositeOp * compositeOp(const QString & id) const; /** * add a composite op to this colorspace. */ virtual void addCompositeOp(const KoCompositeOp * op); /** * 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. */ virtual const KoColorProfile * profile() 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 color 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& color, quint8 *dst, const KoColorProfile * profile = 0) const = 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 quint8 *src, QColor *c, const KoColorProfile * profile = 0) const = 0; /** * Convert the pixels in data to (8-bit BGRA) QImage using the specified profiles. * * @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 */ virtual QImage convertToQImage(const quint8 *data, qint32 width, qint32 height, const KoColorProfile * dstProfile, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const; /** * Convert the specified data to Lab (D50). 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 quint8 * src, quint8 * dst, quint32 nPixels) const; /** * Convert the specified data from Lab (D50). 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 quint8 * src, quint8 * dst, quint32 nPixels) const; /** * Convert the specified data to sRGB 16 bits. 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 toRgbA16(const quint8 * src, quint8 * dst, quint32 nPixels) const; /** * Convert the specified data from sRGB 16 bits. to this colorspace. All colorspaces are * guaranteed to support this. * * @param src the pixels in 16 bit rgb format * @param dst the destination data * @param nPixels the number of pixels in the array */ virtual void fromRgbA16(const quint8 * src, quint8 * dst, quint32 nPixels) const; /** * Create a color conversion transformation. */ virtual KoColorConversionTransformation* createColorConverter(const KoColorSpace * dstColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const; /** * 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 * * This function is not thread-safe. If you want to apply multiple conversion * in different threads at the same time, you need to create one color converter * per-thread using createColorConverter. */ virtual bool convertPixelsTo(const quint8 * src, quint8 * dst, const KoColorSpace * dstColorSpace, quint32 numPixels, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const; //============================== 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 quint8 opacityU8(const quint8 * pixel) const = 0; virtual qreal opacityF(const quint8 * 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 setOpacity(quint8 * pixels, quint8 alpha, qint32 nPixels) const = 0; virtual void setOpacity(quint8 * pixels, qreal alpha, qint32 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(quint8 * pixels, quint8 alpha, qint32 nPixels) const = 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(quint8 * pixels, const quint8 * alpha, qint32 nPixels) const = 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(quint8 * pixels, const quint8 * alpha, qint32 nPixels) const = 0; /** * Applies the specified float alpha mask to the pixels. We assume that there are just * as many alpha values as pixels but we do not check this; alpha values have to be between 0.0 and 1.0 */ virtual void applyAlphaNormedFloatMask(quint8 * pixels, const float * alpha, qint32 nPixels) const = 0; /** * Applies the inverted specified float alpha mask to the pixels. We assume that there are just * as many alpha values as pixels but we do not check this; alpha values have to be between 0.0 and 1.0 */ virtual void applyInverseNormedFloatMask(quint8 * pixels, const float * alpha, qint32 nPixels) const = 0; /** * Create an adjustment object for adjusting the brightness and contrast * transferValues is a 256 bins array with values from 0 to 0xFFFF * This function is thread-safe, but you need to create one KoColorTransformation per thread. */ virtual KoColorTransformation *createBrightnessContrastAdjustment(const quint16 *transferValues) const = 0; /** * Create an adjustment object for adjusting individual channels * transferValues is an array of colorChannelCount number of 256 bins array with values from 0 to 0xFFFF * This function is thread-safe, but you need to create one KoColorTransformation per thread. * * The layout of the channels must be the following: * * 0..N-2 - color channels of the pixel; * N-1 - alpha channel of the pixel (if exists) */ virtual KoColorTransformation *createPerChannelAdjustment(const quint16 * const* transferValues) const = 0; /** * Darken all color channels with the given amount. If compensate is true, * the compensation factor will be used to limit the darkening. * */ virtual KoColorTransformation *createDarkenAdjustment(qint32 shade, bool compensate, qreal compensation) const = 0; /** * Invert color channels of the given pixels * This function is thread-safe, but you need to create one KoColorTransformation per thread. */ virtual KoColorTransformation *createInvertTransformation() const = 0; /** * Get the difference between 2 colors, normalized in the range (0,255). Only completely * opaque and completely transparent are taken into account when computing the different; * other transparency levels are not regarded when finding the difference. */ virtual quint8 difference(const quint8* src1, const quint8* src2) const = 0; /** * Get the difference between 2 colors, normalized in the range (0,255). This function * takes the Alpha channel of the pixel into account. Alpha channel has the same * weight as Lightness channel. */ virtual quint8 differenceA(const quint8* src1, const quint8* src2) const = 0; /** * @return the mix color operation of this colorspace (do not delete it locally, it's deleted by the colorspace). */ virtual KoMixColorsOp* mixColorsOp() const; /** * @return the convolution operation of this colorspace (do not delete it locally, it's deleted by the colorspace). */ virtual KoConvolutionOp* convolutionOp() const; /** * Calculate the intensity of the given pixel, scaled down to the range 0-255. XXX: Maybe this should be more flexible */ virtual quint8 intensity8(const quint8 * src) const = 0; /** - * Create a mathematical toolbox compatible with this colorspace - */ - virtual KoID mathToolboxId() const = 0; - - /** - * Compose two arrays of pixels together. If source and target - * are not the same color model, the source pixels will be - * converted to the target model. We're "dst" -- "dst" pixels are always in _this_ - * colorspace. - * - * @param srcSpace the colorspace of the source pixels that will be composited onto "us" - * @param param the information needed for blitting e.g. the source and destination pixel data, - * the opacity and flow, ... - * @param op the composition operator to use, e.g. COPY_OVER - * - */ + * Compose two arrays of pixels together. If source and target + * are not the same color model, the source pixels will be + * converted to the target model. We're "dst" -- "dst" pixels are always in _this_ + * colorspace. + * + * @param srcSpace the colorspace of the source pixels that will be composited onto "us" + * @param param the information needed for blitting e.g. the source and destination pixel data, + * the opacity and flow, ... + * @param op the composition operator to use, e.g. COPY_OVER + * + */ virtual void bitBlt(const KoColorSpace* srcSpace, const KoCompositeOp::ParameterInfo& params, const KoCompositeOp* op, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const; /** * Serialize this color following Create's swatch color specification available * at http://create.freedesktop.org/wiki/index.php/Swatches_-_colour_file_format * * This function doesn't create the element but rather the , * , ... elements. It is assumed that colorElt is the * element. * * @param pixel buffer to serialized * @param colorElt root element for the serialization, it is assumed that this * element is * @param doc is the document containing colorElt */ virtual void colorToXML(const quint8* pixel, QDomDocument& doc, QDomElement& colorElt) const = 0; /** * Unserialize a color following Create's swatch color specification available * at http://create.freedesktop.org/wiki/index.php/Swatches_-_colour_file_format * * @param pixel buffer where the color will be unserialized * @param elt the element to unserialize (, , ) * @return the unserialize color, or an empty color object if the function failed * to unserialize the color */ virtual void colorFromXML(quint8* pixel, const QDomElement& elt) const = 0; KoColorTransformation* createColorTransformation(const QString & id, const QHash & parameters) const; protected: /** * Use this function in the constructor of your colorspace to add the information about a channel. * @param ci a pointer to the information about a channel */ virtual void addChannel(KoChannelInfo * ci); const KoColorConversionTransformation* toLabA16Converter() const; const KoColorConversionTransformation* fromLabA16Converter() const; const KoColorConversionTransformation* toRgbA16Converter() const; const KoColorConversionTransformation* fromRgbA16Converter() const; /** * Returns the thread-local conversion cache. If it doesn't exist * yet, it is created. If it is currently too small, it is resized. */ QVector * threadLocalConversionCache(quint32 size) const; /** * This function defines the behavior of the bitBlt function * when the composition of pixels in different colorspaces is * requested, that is in case: * * srcCS == any * dstCS == this * * 1) preferCompositionInSourceColorSpace() == false, * * the source pixels are first converted to *this color space * and then composition is performed. * * 2) preferCompositionInSourceColorSpace() == true, * * the destination pixels are first converted into *srcCS color * space, then the composition is done, and the result is finally * converted into *this colorspace. * * This is used by alpha8() color space mostly, because it has * weaker representation of the color, so the composition * should be done in CS with richer functionality. */ virtual bool preferCompositionInSourceColorSpace() const; struct Private; Private * const d; }; inline QDebug operator<<(QDebug dbg, const KoColorSpace *cs) { dbg.nospace() << cs->name() << " (" << cs->colorModelId().id() << "," << cs->colorDepthId().id() << " )"; return dbg.space(); } #endif // KOCOLORSPACE_H diff --git a/libs/pigment/KoColorSpaceAbstract.h b/libs/pigment/KoColorSpaceAbstract.h index b9f004858a..10f392b1de 100644 --- a/libs/pigment/KoColorSpaceAbstract.h +++ b/libs/pigment/KoColorSpaceAbstract.h @@ -1,215 +1,211 @@ /* * Copyright (c) 2006 Cyrille Berger * Copyright (c) 2007 Emanuele Tamponi * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 KOCOLORSPACEABSTRACT_H #define KOCOLORSPACEABSTRACT_H #include #include #include #include #include "KoColorSpaceConstants.h" #include #include #include #include "KoColorTransformation.h" #include "KoFallBackColorTransformation.h" #include "KoLabDarkenColorTransformation.h" #include "KoMixColorsOpImpl.h" #include "KoConvolutionOpImpl.h" #include "KoInvertColorTransformation.h" /** * This in an implementation of KoColorSpace which can be used as a base for colorspaces with as many * different channels of the same type. * * The template parameters must be a class which inherits KoColorSpaceTrait (or a class with the same signature). * * SOMETYPE is the type of the channel for instance (quint8, quint32...), * SOMENBOFCHANNELS is the number of channels including the alpha channel * SOMEALPHAPOS is the position of the alpha channel in the pixel (can be equal to -1 if no alpha channel). */ template class KoColorSpaceAbstract : public KoColorSpace { public: KoColorSpaceAbstract(const QString &id, const QString &name) : KoColorSpace(id, name, new KoMixColorsOpImpl< _CSTrait>(), new KoConvolutionOpImpl< _CSTrait>()) { } virtual quint32 colorChannelCount() const { if (_CSTrait::alpha_pos == -1) return _CSTrait::channels_nb; else return _CSTrait::channels_nb - 1; } virtual quint32 channelCount() const { return _CSTrait::channels_nb; } virtual quint32 pixelSize() const { return _CSTrait::pixelSize; } virtual QString channelValueText(const quint8 *pixel, quint32 channelIndex) const { return _CSTrait::channelValueText(pixel, channelIndex); } virtual QString normalisedChannelValueText(const quint8 *pixel, quint32 channelIndex) const { return _CSTrait::normalisedChannelValueText(pixel, channelIndex); } virtual void normalisedChannelsValue(const quint8 *pixel, QVector &channels) const { return _CSTrait::normalisedChannelsValue(pixel, channels); } virtual void fromNormalisedChannelsValue(quint8 *pixel, const QVector &values) const { return _CSTrait::fromNormalisedChannelsValue(pixel, values); } virtual quint8 scaleToU8(const quint8 * srcPixel, qint32 channelIndex) const { typename _CSTrait::channels_type c = _CSTrait::nativeArray(srcPixel)[channelIndex]; return KoColorSpaceMaths::scaleToA(c); } virtual void singleChannelPixel(quint8 *dstPixel, const quint8 *srcPixel, quint32 channelIndex) const { _CSTrait::singleChannelPixel(dstPixel, srcPixel, channelIndex); } virtual quint8 opacityU8(const quint8 * U8_pixel) const { return _CSTrait::opacityU8(U8_pixel); } virtual qreal opacityF(const quint8 * U8_pixel) const { return _CSTrait::opacityF(U8_pixel); } virtual void setOpacity(quint8 * pixels, quint8 alpha, qint32 nPixels) const { _CSTrait::setOpacity(pixels, alpha, nPixels); } virtual void setOpacity(quint8 * pixels, qreal alpha, qint32 nPixels) const { _CSTrait::setOpacity(pixels, alpha, nPixels); } virtual void multiplyAlpha(quint8 * pixels, quint8 alpha, qint32 nPixels) const { _CSTrait::multiplyAlpha(pixels, alpha, nPixels); } virtual void applyAlphaU8Mask(quint8 * pixels, const quint8 * alpha, qint32 nPixels) const { _CSTrait::applyAlphaU8Mask(pixels, alpha, nPixels); } virtual void applyInverseAlphaU8Mask(quint8 * pixels, const quint8 * alpha, qint32 nPixels) const { _CSTrait::applyInverseAlphaU8Mask(pixels, alpha, nPixels); } virtual void applyAlphaNormedFloatMask(quint8 * pixels, const float * alpha, qint32 nPixels) const { _CSTrait::applyAlphaNormedFloatMask(pixels, alpha, nPixels); } virtual void applyInverseNormedFloatMask(quint8 * pixels, const float * alpha, qint32 nPixels) const { _CSTrait::applyInverseAlphaNormedFloatMask(pixels, alpha, nPixels); } virtual quint8 intensity8(const quint8 * src) const { QColor c; const_cast *>(this)->toQColor(src, &c); return static_cast((c.red() * 0.30 + c.green() * 0.59 + c.blue() * 0.11) + 0.5); } virtual KoColorTransformation* createInvertTransformation() const { return new KoInvertColorTransformation(this); } virtual KoColorTransformation *createDarkenAdjustment(qint32 shade, bool compensate, qreal compensation) const { return new KoFallBackColorTransformation(this, KoColorSpaceRegistry::instance()->lab16(""), new KoLabDarkenColorTransformation(shade, compensate, compensation, KoColorSpaceRegistry::instance()->lab16(""))); } - virtual KoID mathToolboxId() const { - return KoID("Basic"); - } - virtual bool convertPixelsTo(const quint8 *src, quint8 *dst, const KoColorSpace *dstColorSpace, quint32 numPixels, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const { // check whether we have the same profile and color model, but only a different bit // depth; in that case we don't convert as such, but scale bool scaleOnly = false; // Note: getting the id() is really, really expensive, so only do that if // we are sure there is a difference between the colorspaces if (!(*this == *dstColorSpace)) { scaleOnly = dstColorSpace->colorModelId().id() == colorModelId().id() && dstColorSpace->colorDepthId().id() != colorDepthId().id() && dstColorSpace->profile()->name() == profile()->name(); } if (scaleOnly && dynamic_cast(dstColorSpace)) { typedef typename _CSTrait::channels_type channels_type; switch(dstColorSpace->channels()[0]->channelValueType()) { case KoChannelInfo::UINT8: scalePixels<_CSTrait::pixelSize, 1, channels_type, quint8>(src, dst, numPixels); return true; // case KoChannelInfo::INT8: // scalePixels<_CSTrait::pixelSize, 1, channels_type, qint8>(src, dst, numPixels); // return true; case KoChannelInfo::UINT16: scalePixels<_CSTrait::pixelSize, 2, channels_type, quint16>(src, dst, numPixels); return true; case KoChannelInfo::INT16: scalePixels<_CSTrait::pixelSize, 2, channels_type, qint16>(src, dst, numPixels); return true; case KoChannelInfo::UINT32: scalePixels<_CSTrait::pixelSize, 4, channels_type, quint32>(src, dst, numPixels); return true; default: break; } } return KoColorSpace::convertPixelsTo(src, dst, dstColorSpace, numPixels, renderingIntent, conversionFlags); } private: template void scalePixels(const quint8* src, quint8* dst, quint32 numPixels) const { qint32 dstPixelSize = dstChannelSize * _CSTrait::channels_nb; for(quint32 i=0; i(src + i * srcPixelSize); TDstChannel* dstPixel = reinterpret_cast(dst + i * dstPixelSize); for(quint32 c=0; c<_CSTrait::channels_nb; ++c) dstPixel[c] = Arithmetic::scale(srcPixel[c]); } } }; #endif // KOCOLORSPACEABSTRACT_H