KOffice – TDE office suite
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

kis_lms_f32_colorspace.cc 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. /*
  2. * Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
  3. * Copyright (c) 2004 Boudewijn Rempt <boud@valdyas.org>
  4. * Copyright (c) 2005 Adrian Page <adrian@pagenet.plus.com>
  5. * Copyright (c) 2005 Cyrille Berger <cberger@cberger.net>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor,
  20. * Boston, MA 02110-1301, USA.
  21. */
  22. #include <config.h>
  23. #include <limits.h>
  24. #include <stdlib.h>
  25. #include LCMS_HEADER
  26. #include <tqimage.h>
  27. #include <kdebug.h>
  28. #include <tdelocale.h>
  29. #include "kis_lms_f32_colorspace.h"
  30. #include "kis_color_conversions.h"
  31. namespace {
  32. const TQ_INT32 MAX_CHANNEL_LMS = 3;
  33. const TQ_INT32 MAX_CHANNEL_LMSA = 4;
  34. }
  35. #include "kis_integer_maths.h"
  36. #define FLOAT_MAX 1.0f //temp
  37. #define EPSILON 1e-6
  38. // FIXME: lcms doesn't support 32-bit float
  39. #define F32_LCMS_TYPE TYPE_BGRA_16
  40. // disable the lcms handling by setting profile=0
  41. KisLmsF32ColorSpace::KisLmsF32ColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile */*p*/) :
  42. KisF32BaseColorSpace(KisID("LMSAF32", i18n("LMS (32-bit float/channel)")), F32_LCMS_TYPE, icSig3colorData, parent, 0)
  43. {
  44. m_channels.push_back(new KisChannelInfo(i18n("Long"), i18n("L"), PIXEL_LONGWAVE * sizeof(float), KisChannelInfo::COLOR, KisChannelInfo::FLOAT32, sizeof(float)));
  45. m_channels.push_back(new KisChannelInfo(i18n("Middle"), i18n("M"), PIXEL_MIDDLEWAVE * sizeof(float), KisChannelInfo::COLOR, KisChannelInfo::FLOAT32, sizeof(float)));
  46. m_channels.push_back(new KisChannelInfo(i18n("Short"), i18n("S"), PIXEL_SHORTWAVE * sizeof(float), KisChannelInfo::COLOR, KisChannelInfo::FLOAT32, sizeof(float)));
  47. m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), PIXEL_ALPHA * sizeof(float), KisChannelInfo::ALPHA, KisChannelInfo::FLOAT32, sizeof(float)));
  48. m_alphaPos = PIXEL_ALPHA * sizeof(float);
  49. }
  50. KisLmsF32ColorSpace::~KisLmsF32ColorSpace()
  51. {
  52. }
  53. void KisLmsF32ColorSpace::setPixel(TQ_UINT8 *dst, float longWave, float middleWave, float shortWave, float alpha) const
  54. {
  55. Pixel *dstPixel = reinterpret_cast<Pixel *>(dst);
  56. dstPixel->longWave = longWave;
  57. dstPixel->middleWave = middleWave;
  58. dstPixel->shortWave = shortWave;
  59. dstPixel->alpha = alpha;
  60. }
  61. void KisLmsF32ColorSpace::getPixel(const TQ_UINT8 *src, float *longWave, float *middleWave, float *shortWave, float *alpha) const
  62. {
  63. const Pixel *srcPixel = reinterpret_cast<const Pixel *>(src);
  64. *longWave = srcPixel->longWave;
  65. *middleWave = srcPixel->middleWave;
  66. *shortWave = srcPixel->shortWave;
  67. *alpha = srcPixel->alpha;
  68. }
  69. void KisLmsF32ColorSpace::fromTQColor(const TQColor& c, TQ_UINT8 *dstU8, KisProfile * /*profile*/)
  70. {
  71. Pixel *dst = reinterpret_cast<Pixel *>(dstU8);
  72. dst->longWave = computeLong(c.red(),c.green(),c.blue());
  73. dst->middleWave = computeMiddle(c.red(),c.green(),c.blue());
  74. dst->shortWave = computeShort(c.red(),c.green(),c.blue());
  75. }
  76. void KisLmsF32ColorSpace::fromTQColor(const TQColor& c, TQ_UINT8 opacity, TQ_UINT8 *dstU8, KisProfile * /*profile*/)
  77. {
  78. Pixel *dst = reinterpret_cast<Pixel *>(dstU8);
  79. dst->longWave = computeLong(c.red(),c.green(),c.blue());
  80. dst->middleWave = computeMiddle(c.red(),c.green(),c.blue());
  81. dst->shortWave = computeShort(c.red(),c.green(),c.blue());
  82. dst->alpha = UINT8_TO_FLOAT(opacity);
  83. }
  84. void KisLmsF32ColorSpace::toTQColor(const TQ_UINT8 *srcU8, TQColor *c, KisProfile * /*profile*/)
  85. {
  86. const Pixel *src = reinterpret_cast<const Pixel *>(srcU8);
  87. c->setRgb(computeRed(src->longWave,src->middleWave,src->shortWave), computeGreen(src->longWave,src->middleWave,src->shortWave), computeBlue(src->longWave,src->middleWave,src->shortWave));
  88. }
  89. void KisLmsF32ColorSpace::toTQColor(const TQ_UINT8 *srcU8, TQColor *c, TQ_UINT8 *opacity, KisProfile * /*profile*/)
  90. {
  91. const Pixel *src = reinterpret_cast<const Pixel *>(srcU8);
  92. c->setRgb(computeRed(src->longWave,src->middleWave,src->shortWave), computeGreen(src->longWave,src->middleWave,src->shortWave), computeBlue(src->longWave,src->middleWave,src->shortWave));
  93. *opacity = FLOAT_TO_UINT8(src->alpha);
  94. }
  95. TQ_UINT8 KisLmsF32ColorSpace::difference(const TQ_UINT8 *src1U8, const TQ_UINT8 *src2U8)
  96. {
  97. const Pixel *src1 = reinterpret_cast<const Pixel *>(src1U8);
  98. const Pixel *src2 = reinterpret_cast<const Pixel *>(src2U8);
  99. return FLOAT_TO_UINT8(TQMAX(TQABS(src2->longWave - src1->longWave),
  100. TQMAX(TQABS(src2->middleWave - src1->middleWave),
  101. TQABS(src2->shortWave - src1->shortWave))));
  102. }
  103. void KisLmsF32ColorSpace::mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const
  104. {
  105. float totalLong = 0, totalMiddle = 0, totalShort = 0, newAlpha = 0;
  106. while (nColors--)
  107. {
  108. const Pixel *pixel = reinterpret_cast<const Pixel *>(*colors);
  109. float alpha = pixel->alpha;
  110. float alphaTimesWeight = alpha * UINT8_TO_FLOAT(*weights);
  111. totalLong += pixel->longWave * alphaTimesWeight;
  112. totalMiddle += pixel->middleWave * alphaTimesWeight;
  113. totalShort += pixel->shortWave * alphaTimesWeight;
  114. newAlpha += alphaTimesWeight;
  115. weights++;
  116. colors++;
  117. }
  118. Q_ASSERT(newAlpha <= F32_OPACITY_OPAQUE);
  119. Pixel *dstPixel = reinterpret_cast<Pixel *>(dst);
  120. dstPixel->alpha = newAlpha;
  121. if (newAlpha > EPSILON) {
  122. totalLong = totalLong / newAlpha;
  123. totalMiddle = totalMiddle / newAlpha;
  124. totalShort = totalShort / newAlpha;
  125. }
  126. dstPixel->longWave = totalLong;
  127. dstPixel->middleWave = totalMiddle;
  128. dstPixel->shortWave = totalShort;
  129. }
  130. TQValueVector<KisChannelInfo *> KisLmsF32ColorSpace::channels() const
  131. {
  132. return m_channels;
  133. }
  134. TQ_UINT32 KisLmsF32ColorSpace::nChannels() const
  135. {
  136. return MAX_CHANNEL_LMSA;
  137. }
  138. TQ_UINT32 KisLmsF32ColorSpace::nColorChannels() const
  139. {
  140. return MAX_CHANNEL_LMS;
  141. }
  142. TQ_UINT32 KisLmsF32ColorSpace::pixelSize() const
  143. {
  144. return MAX_CHANNEL_LMSA * sizeof(float);
  145. }
  146. TQImage KisLmsF32ColorSpace::convertToTQImage(const TQ_UINT8 *dataU8, TQ_INT32 width, TQ_INT32 height,
  147. KisProfile * /*dstProfile*/,
  148. TQ_INT32 /*renderingIntent*/, float /*exposure*/)
  149. {
  150. const float *data = reinterpret_cast<const float *>(dataU8);
  151. TQImage img = TQImage(width, height, 32, 0, TQImage::LittleEndian);
  152. img.setAlphaBuffer(true);
  153. TQ_INT32 i = 0;
  154. uchar *j = img.bits();
  155. while ( i < width * height * MAX_CHANNEL_LMSA) {
  156. double l = *( data + i + PIXEL_LONGWAVE );
  157. double m = *( data + i + PIXEL_MIDDLEWAVE );
  158. double s = *( data + i + PIXEL_SHORTWAVE );
  159. *( j + 3) = FLOAT_TO_UINT8(*( data + i + PIXEL_ALPHA ));
  160. *( j + 2 ) = computeRed(l,m,s);
  161. *( j + 1 ) = computeGreen(l,m,s);
  162. *( j + 0 ) = computeBlue(l,m,s);
  163. i += MAX_CHANNEL_LMSA;
  164. j += MAX_CHANNEL_LMSA;
  165. }
  166. /*
  167. if (srcProfile != 0 && dstProfile != 0) {
  168. convertPixelsTo(img.bits(), srcProfile,
  169. img.bits(), this, dstProfile,
  170. width * height, renderingIntent);
  171. }
  172. */
  173. return img;
  174. }
  175. void KisLmsF32ColorSpace::compositeOver(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *maskRowStart, TQ_INT32 maskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, float opacity)
  176. {
  177. while (rows > 0) {
  178. const float *src = reinterpret_cast<const float *>(srcRowStart);
  179. float *dst = reinterpret_cast<float *>(dstRowStart);
  180. const TQ_UINT8 *mask = maskRowStart;
  181. TQ_INT32 columns = numColumns;
  182. while (columns > 0) {
  183. float srcAlpha = src[PIXEL_ALPHA];
  184. // apply the alphamask
  185. if (mask != 0) {
  186. TQ_UINT8 U8_mask = *mask;
  187. if (U8_mask != OPACITY_OPAQUE) {
  188. srcAlpha *= UINT8_TO_FLOAT(U8_mask);
  189. }
  190. mask++;
  191. }
  192. if (srcAlpha > F32_OPACITY_TRANSPARENT + EPSILON) {
  193. if (opacity < F32_OPACITY_OPAQUE - EPSILON) {
  194. srcAlpha *= opacity;
  195. }
  196. if (srcAlpha > F32_OPACITY_OPAQUE - EPSILON) {
  197. memcpy(dst, src, MAX_CHANNEL_LMSA * sizeof(float));
  198. } else {
  199. float dstAlpha = dst[PIXEL_ALPHA];
  200. float srcBlend;
  201. if (dstAlpha > F32_OPACITY_OPAQUE - EPSILON) {
  202. srcBlend = srcAlpha;
  203. } else {
  204. float newAlpha = dstAlpha + (F32_OPACITY_OPAQUE - dstAlpha) * srcAlpha;
  205. dst[PIXEL_ALPHA] = newAlpha;
  206. if (newAlpha > EPSILON) {
  207. srcBlend = srcAlpha / newAlpha;
  208. } else {
  209. srcBlend = srcAlpha;
  210. }
  211. }
  212. if (srcBlend > F32_OPACITY_OPAQUE - EPSILON) {
  213. memcpy(dst, src, MAX_CHANNEL_LMS * sizeof(float));
  214. } else {
  215. dst[PIXEL_LONGWAVE] = FLOAT_BLEND(src[PIXEL_LONGWAVE], dst[PIXEL_LONGWAVE], srcBlend);
  216. dst[PIXEL_MIDDLEWAVE] = FLOAT_BLEND(src[PIXEL_MIDDLEWAVE], dst[PIXEL_MIDDLEWAVE], srcBlend);
  217. dst[PIXEL_SHORTWAVE] = FLOAT_BLEND(src[PIXEL_SHORTWAVE], dst[PIXEL_SHORTWAVE], srcBlend);
  218. }
  219. }
  220. }
  221. columns--;
  222. src += MAX_CHANNEL_LMSA;
  223. dst += MAX_CHANNEL_LMSA;
  224. }
  225. rows--;
  226. srcRowStart += srcRowStride;
  227. dstRowStart += dstRowStride;
  228. if(maskRowStart) {
  229. maskRowStart += maskRowStride;
  230. }
  231. }
  232. }
  233. void KisLmsF32ColorSpace::compositeErase(TQ_UINT8 *dst,
  234. TQ_INT32 dstRowSize,
  235. const TQ_UINT8 *src,
  236. TQ_INT32 srcRowSize,
  237. const TQ_UINT8 *srcAlphaMask,
  238. TQ_INT32 maskRowStride,
  239. TQ_INT32 rows,
  240. TQ_INT32 cols,
  241. float /*opacity*/)
  242. {
  243. while (rows-- > 0)
  244. {
  245. const Pixel *s = reinterpret_cast<const Pixel *>(src);
  246. Pixel *d = reinterpret_cast<Pixel *>(dst);
  247. const TQ_UINT8 *mask = srcAlphaMask;
  248. for (TQ_INT32 i = cols; i > 0; i--, s++, d++)
  249. {
  250. float srcAlpha = s->alpha;
  251. // apply the alphamask
  252. if (mask != 0) {
  253. TQ_UINT8 U8_mask = *mask;
  254. if (U8_mask != OPACITY_OPAQUE) {
  255. srcAlpha = FLOAT_BLEND(srcAlpha, F32_OPACITY_OPAQUE, UINT8_TO_FLOAT(U8_mask));
  256. }
  257. mask++;
  258. }
  259. d->alpha = srcAlpha * d->alpha;
  260. }
  261. dst += dstRowSize;
  262. src += srcRowSize;
  263. if(srcAlphaMask) {
  264. srcAlphaMask += maskRowStride;
  265. }
  266. }
  267. }
  268. void KisLmsF32ColorSpace::compositeCopy(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride,
  269. const TQ_UINT8 */*maskRowStart*/, TQ_INT32 /*maskRowStride*/, TQ_INT32 rows, TQ_INT32 numColumns, float /*opacity*/)
  270. {
  271. while (rows > 0) {
  272. memcpy(dstRowStart, srcRowStart, numColumns * sizeof(Pixel));
  273. --rows;
  274. srcRowStart += srcRowStride;
  275. dstRowStart += dstRowStride;
  276. }
  277. }
  278. void KisLmsF32ColorSpace::bitBlt(TQ_UINT8 *dst,
  279. TQ_INT32 dstRowStride,
  280. const TQ_UINT8 *src,
  281. TQ_INT32 srcRowStride,
  282. const TQ_UINT8 *mask,
  283. TQ_INT32 maskRowStride,
  284. TQ_UINT8 U8_opacity,
  285. TQ_INT32 rows,
  286. TQ_INT32 cols,
  287. const KisCompositeOp& op)
  288. {
  289. float opacity = UINT8_TO_FLOAT(U8_opacity);
  290. switch (op.op()) {
  291. case COMPOSITE_UNDEF:
  292. // Undefined == no composition
  293. break;
  294. case COMPOSITE_OVER:
  295. compositeOver(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
  296. break;
  297. case COMPOSITE_COPY:
  298. compositeCopy(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
  299. break;
  300. case COMPOSITE_ERASE:
  301. compositeErase(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
  302. break;
  303. default:
  304. break;
  305. }
  306. }
  307. KisCompositeOpList KisLmsF32ColorSpace::userVisiblecompositeOps() const
  308. {
  309. KisCompositeOpList list;
  310. list.append(KisCompositeOp(COMPOSITE_OVER));
  311. return list;
  312. }