File indexing completed on 2024-06-09 04:23:29

0001 /*
0002  * SPDX-FileCopyrightText: 2011 Silvio Heinrich <plassy@web.de>
0003  *
0004  * SPDX-License-Identifier: LGPL-2.1-or-later
0005 */
0006 
0007 #ifndef _KOCOMPOSITEOP_DISSOLVE_H_
0008 #define _KOCOMPOSITEOP_DISSOLVE_H_
0009 
0010 #include <KoCompositeOp.h>
0011 #include <KoColorSpaceMaths.h>
0012 
0013 template<class Traits>
0014 class KoCompositeOpDissolve: public KoCompositeOp
0015 {
0016     typedef typename Traits::channels_type channels_type;
0017 
0018     static const qint32 channels_nb = Traits::channels_nb;
0019     static const qint32 alpha_pos   = Traits::alpha_pos;
0020 
0021     inline static quint8 getRandomValue(quint32 i)
0022     {
0023         static const quint8 randomValues[256] =
0024         {
0025             0x50, 0xAD, 0x7D, 0xA9, 0x10, 0x75, 0xCA, 0x57, 0xE2, 0x06, 0x77, 0x39, 0xD9, 0xFA, 0x5C, 0x24,
0026             0xEB, 0x1A, 0x6F, 0x15, 0xE7, 0x8B, 0x11, 0x71, 0xF0, 0xB9, 0x44, 0x8A, 0x27, 0x5E, 0xA1, 0x6A,
0027             0x47, 0x94, 0x03, 0xD5, 0xB7, 0x56, 0xEF, 0x45, 0xED, 0xBE, 0xE8, 0xB2, 0x4C, 0x0D, 0x65, 0x9E,
0028             0x55, 0xD7, 0x30, 0x0F, 0x52, 0xA6, 0x4D, 0x86, 0xAF, 0x66, 0x33, 0x6B, 0x3E, 0x89, 0xBD, 0xFB,
0029             0x00, 0xC4, 0x36, 0xFC, 0x8D, 0x4E, 0x19, 0x3F, 0x91, 0xC1, 0x40, 0x14, 0x67, 0x80, 0x17, 0x3A,
0030             0xF2, 0xB4, 0xD1, 0xFF, 0x35, 0xA7, 0xF7, 0x1C, 0x84, 0x2A, 0xBF, 0x46, 0xC6, 0x2B, 0x98, 0x41,
0031             0xF4, 0xB8, 0xA0, 0x78, 0x5A, 0xBC, 0x3B, 0x62, 0xB6, 0x7A, 0x2E, 0x07, 0x8F, 0x4A, 0xAB, 0x2F,
0032             0x79, 0x54, 0x81, 0x69, 0x18, 0x4F, 0xA5, 0x21, 0xD3, 0x26, 0x7C, 0x9F, 0xCF, 0xB0, 0x34, 0xCC,
0033             0x8C, 0xAA, 0xDB, 0x32, 0xE5, 0x1F, 0x7B, 0x37, 0x64, 0x0A, 0xF9, 0x63, 0xF5, 0x38, 0x13, 0xA2,
0034             0x12, 0xF6, 0xC9, 0x5D, 0xDF, 0xC7, 0x97, 0xC0, 0x51, 0xE1, 0x9A, 0x58, 0x76, 0xC3, 0x83, 0xC2,
0035             0x04, 0x22, 0x60, 0x9D, 0xF1, 0x5F, 0xEC, 0x6D, 0x4B, 0xE0, 0x6C, 0xD8, 0xAC, 0x25, 0xA8, 0x1E,
0036             0x96, 0x7E, 0x49, 0x61, 0xCD, 0x0E, 0xE3, 0xC5, 0x7F, 0x5B, 0x05, 0x6E, 0xBA, 0x0C, 0x8E, 0xF8,
0037             0x82, 0xDA, 0x72, 0x01, 0x23, 0x9B, 0xD2, 0x99, 0xE9, 0xC8, 0xB1, 0x28, 0xD4, 0xAE, 0x48, 0xFD,
0038             0x95, 0x2C, 0xE4, 0x93, 0x09, 0x3D, 0x70, 0x85, 0x43, 0x20, 0xBB, 0xDE, 0x90, 0xB3, 0x3C, 0xDD,
0039             0xA3, 0x73, 0x9C, 0x16, 0xDC, 0x42, 0xEA, 0x74, 0x92, 0xE6, 0xCB, 0x53, 0x08, 0xEE, 0x59, 0x02,
0040             0xF3, 0x29, 0xFE, 0xA4, 0x1B, 0xD6, 0x87, 0xB5, 0xCE, 0x1D, 0x68, 0x88, 0x31, 0x0B, 0x2D, 0xD0
0041         };
0042 
0043         return randomValues[i];
0044     }
0045 
0046 public:
0047     KoCompositeOpDissolve(const KoColorSpace* cs, const QString& category)
0048         : KoCompositeOp(cs, COMPOSITE_DISSOLVE, category) { }
0049 
0050     using KoCompositeOp::composite;
0051 
0052     void composite(quint8*       dstRowStart , qint32 dstRowStride ,
0053                            const quint8* srcRowStart , qint32 srcRowStride ,
0054                            const quint8* maskRowStart, qint32 maskRowStride,
0055                            qint32 rows, qint32 cols, quint8 U8_opacity, const QBitArray& channelFlags) const override {
0056 
0057         const QBitArray& flags       = channelFlags.isEmpty() ? QBitArray(channels_nb,true) : channelFlags;
0058         bool             alphaLocked = (alpha_pos != -1) && !flags.testBit(alpha_pos);
0059 
0060         using namespace Arithmetic;
0061 
0062 //         quint32       ctr       = quint32(reinterpret_cast<quint64>(dstRowStart) % 256);
0063         qint32        srcInc    = (srcRowStride == 0) ? 0 : channels_nb;
0064         bool          useMask   = maskRowStart != 0;
0065         channels_type unitValue = KoColorSpaceMathsTraits<channels_type>::unitValue;
0066         channels_type opacity   = KoColorSpaceMaths<quint8,channels_type>::scaleToA(U8_opacity);
0067 
0068         for(; rows>0; --rows) {
0069             const channels_type* src  = reinterpret_cast<const channels_type*>(srcRowStart);
0070             channels_type*       dst  = reinterpret_cast<channels_type*>(dstRowStart);
0071             const quint8*        mask = maskRowStart;
0072 
0073             for(qint32 c=cols; c>0; --c) {
0074                 channels_type srcAlpha = (alpha_pos == -1) ? unitValue : src[alpha_pos];
0075                 channels_type dstAlpha = (alpha_pos == -1) ? unitValue : dst[alpha_pos];
0076                 channels_type blend    = useMask ? mul(opacity, scale<channels_type>(*mask), srcAlpha) : mul(opacity, srcAlpha);
0077 
0078 //                 if(getRandomValue(ctr) <= scale<quint8>(blend) && blend != KoColorSpaceMathsTraits<channels_type>::zeroValue) {
0079                 if((qrand() % 256) <= scale<quint8>(blend) && blend != KoColorSpaceMathsTraits<channels_type>::zeroValue) {
0080                     for(qint32 i=0; i <channels_nb; i++) {
0081                         if(i != alpha_pos && flags.testBit(i))
0082                             dst[i] = src[i];
0083                     }
0084 
0085                     if(alpha_pos != -1)
0086                         dst[alpha_pos] = alphaLocked ? dstAlpha : unitValue;
0087                 }
0088 
0089                 src += srcInc;
0090                 dst += channels_nb;
0091 //                 ctr  = (ctr + 1) % 256;
0092                 if (mask) {
0093                     ++mask;
0094                 }
0095             }
0096 
0097             srcRowStart  += srcRowStride;
0098             dstRowStart  += dstRowStride;
0099             if (maskRowStart) {
0100                 maskRowStart += maskRowStride;
0101             }
0102         }
0103     }
0104 };
0105 
0106 #endif // _KOCOMPOSITEOP_DISSOLVE_H_