File indexing completed on 2024-05-19 04:22:56
0001 0002 /* 0003 Copyright (c) 2003-2007 Clarence Dang <dang@kde.org> 0004 Copyright (c) 2011 Martin Koller <kollix@aon.at> 0005 All rights reserved. 0006 0007 Redistribution and use in source and binary forms, with or without 0008 modification, are permitted provided that the following conditions 0009 are met: 0010 0011 1. Redistributions of source code must retain the above copyright 0012 notice, this list of conditions and the following disclaimer. 0013 2. Redistributions in binary form must reproduce the above copyright 0014 notice, this list of conditions and the following disclaimer in the 0015 documentation and/or other materials provided with the distribution. 0016 0017 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 0018 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 0019 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 0020 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 0021 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 0022 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 0023 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 0024 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 0025 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 0026 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 0027 */ 0028 0029 0030 #define DEBUG_KP_EFFECT_REDUCE_COLORS 0 0031 0032 0033 #include "imagelib/effects/kpEffectReduceColors.h" 0034 0035 #include "kpLogCategories.h" 0036 0037 //--------------------------------------------------------------------- 0038 0039 static QImage::Format DepthToFormat (int depth) 0040 { 0041 // These values are QImage's supported depths. 0042 switch (depth) 0043 { 0044 case 1: 0045 // (can be MSB instead, I suppose) 0046 return QImage::Format_MonoLSB; 0047 0048 case 8: 0049 return QImage::Format_Indexed8; 0050 0051 case 16: 0052 return QImage::Format_ARGB4444_Premultiplied; 0053 0054 case 24: 0055 return QImage::Format_ARGB6666_Premultiplied; 0056 0057 case 32: 0058 return QImage::Format_ARGB32_Premultiplied; 0059 0060 default: 0061 Q_ASSERT (!"unknown depth"); 0062 return QImage::Format_Invalid; 0063 } 0064 } 0065 0066 //--------------------------------------------------------------------- 0067 0068 // public static 0069 QImage kpEffectReduceColors::convertImageDepth (const QImage &image, int depth, bool dither) 0070 { 0071 #if DEBUG_KP_EFFECT_REDUCE_COLORS 0072 qCDebug(kpLogImagelib) << "kpeffectreducecolors.cpp:ConvertImageDepth() changing image (w=" << image.width () 0073 << ",h=" << image.height () 0074 << ") depth from " << image.depth () 0075 << " to " << depth 0076 << " (dither=" << dither << ")" 0077 << endl; 0078 #endif 0079 0080 if (image.isNull ()) { 0081 return image; 0082 } 0083 0084 if (depth == image.depth ()) { 0085 return image; 0086 } 0087 0088 0089 #if DEBUG_KP_EFFECT_REDUCE_COLORS && 0 0090 for (int y = 0; y < image.height (); y++) 0091 { 0092 for (int x = 0; x < image.width (); x++) 0093 { 0094 fprintf (stderr, " %08X", image.pixel (x, y)); 0095 } 0096 fprintf (stderr, "\n"); 0097 } 0098 #endif 0099 0100 0101 // Hack around Qt's braindead QImage::convertToFormat(QImage::Format_MonoLSB, ...) 0102 // (with dithering off) which produces pathetic results with an image that 0103 // only has 2 colors - sometimes it just gives a completely black 0104 // result (try yellow and white as input). Instead, we simply preserve 0105 // the 2 colours. 0106 // 0107 // One use case is resaving a "color monochrome" image (<= 2 colors but 0108 // not necessarily black & white). 0109 if (depth == 1 && !dither) 0110 { 0111 #if DEBUG_KP_EFFECT_REDUCE_COLORS 0112 qCDebug(kpLogImagelib) << "\tinvoking convert-to-depth 1 hack"; 0113 #endif 0114 QRgb color0 = 0, color1 = 0; 0115 bool color0Valid = false, color1Valid = false; 0116 0117 bool moreThan2Colors = false; 0118 0119 QImage monoImage (image.width (), image.height (), QImage::Format_MonoLSB); 0120 monoImage.setColorCount (2); 0121 #if DEBUG_KP_EFFECT_REDUCE_COLORS 0122 qCDebug(kpLogImagelib) << "\t\tinitialising output image w=" << monoImage.width () 0123 << ",h=" << monoImage.height () 0124 << ",d=" << monoImage.depth (); 0125 #endif 0126 for (int y = 0; y < image.height (); y++) 0127 { 0128 for (int x = 0; x < image.width (); x++) 0129 { 0130 // (this can be transparent) 0131 QRgb imagePixel = image.pixel (x, y); 0132 0133 if (color0Valid && imagePixel == color0) { 0134 monoImage.setPixel (x, y, 0); 0135 } 0136 else if (color1Valid && imagePixel == color1) { 0137 monoImage.setPixel (x, y, 1); 0138 } 0139 else if (!color0Valid) { 0140 color0 = imagePixel; 0141 color0Valid = true; 0142 monoImage.setPixel (x, y, 0); 0143 #if DEBUG_KP_EFFECT_REDUCE_COLORS 0144 qCDebug(kpLogImagelib) << "\t\t\tcolor0=" << (int *) color0 0145 << " at x=" << x << ",y=" << y; 0146 #endif 0147 } 0148 else if (!color1Valid) 0149 { 0150 color1 = imagePixel; 0151 color1Valid = true; 0152 monoImage.setPixel (x, y, 1); 0153 #if DEBUG_KP_EFFECT_REDUCE_COLORS 0154 qCDebug(kpLogImagelib) << "\t\t\tcolor1=" << (int *) color1 0155 << " at x=" << x << ",y=" << y; 0156 #endif 0157 } 0158 else 0159 { 0160 #if DEBUG_KP_EFFECT_REDUCE_COLORS 0161 qCDebug(kpLogImagelib) << "\t\t\timagePixel=" << (int *) imagePixel 0162 << " at x=" << x << ",y=" << y 0163 << " moreThan2Colors - abort hack"; 0164 #endif 0165 moreThan2Colors = true; 0166 0167 // Dijkstra, this is clearer than double break'ing or 0168 // a check in both loops 0169 goto exit_loop; 0170 } 0171 } 0172 } 0173 exit_loop: 0174 0175 if (!moreThan2Colors) 0176 { 0177 monoImage.setColor (0, color0Valid ? color0 : 0xFFFFFF); 0178 monoImage.setColor (1, color1Valid ? color1 : 0x000000); 0179 return monoImage; 0180 } 0181 } 0182 0183 QImage retImage = image.convertToFormat (::DepthToFormat (depth), 0184 Qt::AutoColor | 0185 (dither ? Qt::DiffuseDither : Qt::ThresholdDither) | 0186 Qt::ThresholdAlphaDither | 0187 (dither ? Qt::PreferDither : Qt::AvoidDither)); 0188 #if DEBUG_KP_EFFECT_REDUCE_COLORS 0189 qCDebug(kpLogImagelib) << "\tformat: before=" << image.format () 0190 << "after=" << retImage.format (); 0191 #endif 0192 0193 #if DEBUG_KP_EFFECT_REDUCE_COLORS && 0 0194 qCDebug(kpLogImagelib) << "After colour reduction:"; 0195 for (int y = 0; y < image.height (); y++) 0196 { 0197 for (int x = 0; x < image.width (); x++) 0198 { 0199 fprintf (stderr, " %08X", image.pixel (x, y)); 0200 } 0201 fprintf (stderr, "\n"); 0202 } 0203 #endif 0204 0205 return retImage; 0206 } 0207 0208 //--------------------------------------------------------------------- 0209 0210 // public static 0211 void kpEffectReduceColors::applyEffect (QImage *destPtr, int depth, bool dither) 0212 { 0213 if (!destPtr) { 0214 return; 0215 } 0216 0217 // You can't "reduce" to 32-bit since it's the highest depth. 0218 if (depth != 1 && depth != 8) { 0219 return; 0220 } 0221 0222 *destPtr = convertImageDepth(*destPtr, depth, dither); 0223 0224 // internally we always use QImage::Format_ARGB32_Premultiplied and 0225 // this effect is just an "effect" in that it changes the image (the look) somehow 0226 // When one wants a different depth on the file, then he needs to save the image 0227 // in that depth 0228 destPtr->convertTo(QImage::Format_ARGB32_Premultiplied); 0229 } 0230 0231 //--------------------------------------------------------------------- 0232 0233 QImage kpEffectReduceColors::applyEffect (const QImage &pm, int depth, bool dither) 0234 { 0235 QImage ret = pm; 0236 applyEffect (&ret, depth, dither); 0237 return ret; 0238 } 0239 0240 //---------------------------------------------------------------------