File indexing completed on 2024-06-09 04:21:59
0001 /* 0002 * SPDX-FileCopyrightText: 2016 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #ifndef __KIS_LAZY_FILL_CAPACITY_MAP_H 0008 #define __KIS_LAZY_FILL_CAPACITY_MAP_H 0009 0010 #include <KoColorSpace.h> 0011 0012 #include "kis_lazy_fill_graph.h" 0013 #include "kis_paint_device.h" 0014 #include "kis_types.h" 0015 #include "kis_painter.h" 0016 #include "kis_random_accessor_ng.h" 0017 #include "kis_global.h" 0018 #include <KisRegion.h> 0019 0020 0021 class KisLazyFillCapacityMap 0022 { 0023 typedef KisLazyFillCapacityMap type; 0024 typedef typename boost::graph_traits<KisLazyFillGraph>::vertex_descriptor VertexDescriptor; 0025 typedef typename boost::graph_traits<KisLazyFillGraph>::edge_descriptor EdgeDescriptor; 0026 0027 public: 0028 typedef EdgeDescriptor key_type; 0029 typedef int value_type; 0030 typedef const int& reference; 0031 typedef boost::readable_property_map_tag category; 0032 0033 KisLazyFillCapacityMap(KisPaintDeviceSP mainImage, 0034 KisPaintDeviceSP aLabelImage, 0035 KisPaintDeviceSP bLabelImage, 0036 KisPaintDeviceSP maskImage, 0037 const QRect &boundingRect) 0038 : m_mainImage(mainImage), 0039 m_aLabelImage(aLabelImage), 0040 m_bLabelImage(bLabelImage), 0041 m_maskImage(maskImage), 0042 m_mainRect(boundingRect), 0043 m_aLabelRect(m_aLabelImage->exactBounds() & boundingRect), 0044 m_bLabelRect(m_bLabelImage->exactBounds() & boundingRect), 0045 m_colorSpace(mainImage->colorSpace()), 0046 m_pixelSize(m_colorSpace->pixelSize()), 0047 m_graph(m_mainRect, 0048 m_aLabelImage->regionExact() & boundingRect, 0049 m_bLabelImage->regionExact() & boundingRect) 0050 { 0051 KIS_ASSERT_RECOVER_NOOP(m_mainImage->colorSpace()->pixelSize() == 1); 0052 KIS_ASSERT_RECOVER_NOOP(m_aLabelImage->colorSpace()->pixelSize() == 1); 0053 KIS_ASSERT_RECOVER_NOOP(m_bLabelImage->colorSpace()->pixelSize() == 1); 0054 0055 m_mainAccessor = m_mainImage->createRandomConstAccessorNG(); 0056 m_aAccessor = m_aLabelImage->createRandomConstAccessorNG(); 0057 m_bAccessor = m_bLabelImage->createRandomConstAccessorNG(); 0058 m_maskAccessor = m_maskImage->createRandomConstAccessorNG(); 0059 m_srcPixelBuf.resize(m_pixelSize); 0060 } 0061 0062 int maxCapacity() const { 0063 const int k = 2 * (m_mainRect.width() + m_mainRect.height()); 0064 return k + 1; 0065 } 0066 0067 friend value_type get(type &map, 0068 const key_type &key) 0069 { 0070 VertexDescriptor src = source(key, map.m_graph); 0071 VertexDescriptor dst = target(key, map.m_graph); 0072 0073 if (src.type == VertexDescriptor::NORMAL) { 0074 map.m_maskAccessor->moveTo(src.x, src.y); 0075 if (*map.m_maskAccessor->rawDataConst()) { 0076 return 0; 0077 } 0078 } 0079 0080 if (dst.type == VertexDescriptor::NORMAL) { 0081 map.m_maskAccessor->moveTo(dst.x, dst.y); 0082 if (*map.m_maskAccessor->rawDataConst()) { 0083 return 0; 0084 } 0085 } 0086 0087 bool srcLabelA = src.type == VertexDescriptor::LABEL_A; 0088 bool srcLabelB = src.type == VertexDescriptor::LABEL_B; 0089 bool dstLabelA = dst.type == VertexDescriptor::LABEL_A; 0090 bool dstLabelB = dst.type == VertexDescriptor::LABEL_B; 0091 0092 if (srcLabelA || srcLabelB) { 0093 std::swap(src, dst); 0094 std::swap(srcLabelA, dstLabelA); 0095 std::swap(srcLabelB, dstLabelB); 0096 } 0097 0098 Q_ASSERT(!srcLabelA && !srcLabelB); 0099 0100 0101 // TODO: precalculate! 0102 const int k = 2 * (map.m_mainRect.width() + map.m_mainRect.height()); 0103 0104 static const int unitValue = 256; 0105 0106 qreal value = 0.0; 0107 0108 if (dstLabelA) { 0109 map.m_aAccessor->moveTo(src.x, src.y); 0110 const int i0 = *((quint8*)map.m_aAccessor->rawDataConst()); 0111 value = i0 / 255.0 * k; 0112 0113 } else if (dstLabelB) { 0114 map.m_bAccessor->moveTo(src.x, src.y); 0115 const int i0 = *((quint8*)map.m_bAccessor->rawDataConst()); 0116 value = i0 / 255.0 * k; 0117 0118 } else { 0119 map.m_mainAccessor->moveTo(src.x, src.y); 0120 memcpy(map.m_srcPixelBuf.data(), map.m_mainAccessor->rawDataConst(), map.m_pixelSize); 0121 map.m_mainAccessor->moveTo(dst.x, dst.y); 0122 0123 //const quint8 diff = map.m_colorSpace->differenceA((quint8*)map.m_srcPixelBuf.data(), map.m_mainAccessor->rawDataConst()); 0124 //const quint8 i0 = map.m_colorSpace->intensity8((quint8*)map.m_srcPixelBuf.data()); 0125 //const quint8 i1 = map.m_colorSpace->intensity8(map.m_mainAccessor->rawDataConst()); 0126 0127 const quint8 i0 = *((quint8*)map.m_srcPixelBuf.data()); 0128 const quint8 i1 = *map.m_mainAccessor->rawDataConst(); 0129 0130 const quint8 diff = qAbs(i1 - i0); 0131 0132 const qreal diffPenalty = qBound(0.0, qreal(diff) / 10.0, 1.0); 0133 const qreal intensityPenalty = 1.0 - i1 / 255.0; 0134 0135 const qreal totalPenalty = qMax(0.0 * diffPenalty, intensityPenalty); 0136 0137 value = 1.0 + k * (1.0 - pow2(totalPenalty)); 0138 } 0139 0140 return value * unitValue; 0141 } 0142 0143 KisLazyFillGraph& graph() { 0144 return m_graph; 0145 } 0146 0147 private: 0148 KisPaintDeviceSP m_mainImage; 0149 KisPaintDeviceSP m_aLabelImage; 0150 KisPaintDeviceSP m_bLabelImage; 0151 KisPaintDeviceSP m_maskImage; 0152 0153 QRect m_mainRect; 0154 QRect m_aLabelRect; 0155 QRect m_bLabelRect; 0156 0157 const KoColorSpace *m_colorSpace; 0158 int m_pixelSize; 0159 KisRandomConstAccessorSP m_mainAccessor; 0160 KisRandomConstAccessorSP m_aAccessor; 0161 KisRandomConstAccessorSP m_bAccessor; 0162 KisRandomConstAccessorSP m_maskAccessor; 0163 QByteArray m_srcPixelBuf; 0164 0165 KisLazyFillGraph m_graph; 0166 }; 0167 0168 #endif /* __KIS_LAZY_FILL_CAPACITY_MAP_H */