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_basic_histogram_producers.cc 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. /*
  2. * Copyright (c) 2005 Bart Coppens <kde@bartcoppens.be>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  17. */
  18. #include <tqstring.h>
  19. #include <tdelocale.h>
  20. #include "config.h"
  21. #ifdef HAVE_OPENEXR
  22. #include <half.h>
  23. #endif
  24. #include "kis_global.h"
  25. #include "kis_basic_histogram_producers.h"
  26. #include "kis_integer_maths.h"
  27. #include "kis_channelinfo.h"
  28. #include "kis_colorspace.h"
  29. #include "kis_lab_colorspace.h"
  30. KisLabColorSpace* KisGenericLabHistogramProducer::m_labCs = 0;
  31. KisBasicHistogramProducer::KisBasicHistogramProducer(const KisID& id, int channels, int nrOfBins, KisColorSpace *cs)
  32. : m_channels(channels),
  33. m_nrOfBins(nrOfBins),
  34. m_colorSpace(cs),
  35. m_id(id)
  36. {
  37. m_bins.resize(m_channels);
  38. for (int i = 0; i < m_channels; i++)
  39. m_bins.at(i).resize(m_nrOfBins);
  40. m_outLeft.resize(m_channels);
  41. m_outRight.resize(m_channels);
  42. m_count = 0;
  43. m_from = 0.0;
  44. m_width = 1.0;
  45. }
  46. void KisBasicHistogramProducer::clear() {
  47. m_count = 0;
  48. for (int i = 0; i < m_channels; i++) {
  49. for (int j = 0; j < m_nrOfBins; j++) {
  50. m_bins.at(i).at(j) = 0;
  51. }
  52. m_outRight.at(i) = 0;
  53. m_outLeft.at(i) = 0;
  54. }
  55. }
  56. void KisBasicHistogramProducer::makeExternalToInternal() {
  57. // This function assumes that the pixel is has no 'gaps'. That is to say: if we start
  58. // at byte 0, we can get to the end of the pixel by adding consecutive size()s of
  59. // the channels
  60. TQValueVector<KisChannelInfo *> c = channels();
  61. uint count = c.count();
  62. int currentPos = 0;
  63. for (uint i = 0; i < count; i++) {
  64. for (uint j = 0; j < count; j++) {
  65. if (c.at(j)->pos() == currentPos) {
  66. m_external.append(j);
  67. break;
  68. }
  69. }
  70. currentPos += c.at(m_external.at(m_external.count() - 1))->size();
  71. }
  72. }
  73. // ------------ U8 ---------------------
  74. KisBasicU8HistogramProducer::KisBasicU8HistogramProducer(const KisID& id, KisColorSpace *cs)
  75. : KisBasicHistogramProducer(id, cs->nChannels(), 256, cs)
  76. {
  77. }
  78. TQString KisBasicU8HistogramProducer::positionToString(double pos) const {
  79. return TQString("%1").arg(static_cast<TQ_UINT8>(pos * UINT8_MAX));
  80. }
  81. void KisBasicU8HistogramProducer::addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *cs)
  82. {
  83. if (!pixels) return;
  84. if (!cs) return;
  85. if (nPixels == 0) return;
  86. TQ_INT32 pSize = cs->pixelSize();
  87. if ( selectionMask ) {
  88. while (nPixels > 0) {
  89. if ( ! (m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT) ) {
  90. for (int i = 0; i < m_channels; i++) {
  91. m_bins.at(i).at(pixels[i])++;
  92. }
  93. m_count++;
  94. }
  95. pixels += pSize;
  96. selectionMask++;
  97. nPixels--;
  98. }
  99. }
  100. else {
  101. while (nPixels > 0) {
  102. if ( ! (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT) ) {
  103. for (int i = 0; i < m_channels; i++) {
  104. m_bins.at(i).at(pixels[i])++;
  105. }
  106. m_count++;
  107. }
  108. pixels += pSize;
  109. nPixels--;
  110. }
  111. }
  112. }
  113. // ------------ U16 ---------------------
  114. KisBasicU16HistogramProducer::KisBasicU16HistogramProducer(const KisID& id, KisColorSpace *cs)
  115. : KisBasicHistogramProducer(id, cs->nChannels(), 256, cs)
  116. {
  117. }
  118. TQString KisBasicU16HistogramProducer::positionToString(double pos) const
  119. {
  120. return TQString("%1").arg(static_cast<TQ_UINT8>(pos * UINT8_MAX));
  121. }
  122. double KisBasicU16HistogramProducer::maximalZoom() const
  123. {
  124. return 1.0 / 255.0;
  125. }
  126. void KisBasicU16HistogramProducer::addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *cs)
  127. {
  128. // The view
  129. TQ_UINT16 from = static_cast<TQ_UINT16>(m_from * UINT16_MAX);
  130. TQ_UINT16 width = static_cast<TQ_UINT16>(m_width * UINT16_MAX + 0.5); // We include the end
  131. TQ_UINT16 to = from + width;
  132. double factor = 255.0 / width;
  133. TQ_INT32 pSize = cs->pixelSize();
  134. if ( selectionMask ) {
  135. TQ_UINT16* pixel = reinterpret_cast<TQ_UINT16*>(pixels);
  136. while (nPixels > 0) {
  137. if ( ! ((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) {
  138. for (int i = 0; i < m_channels; i++) {
  139. TQ_UINT16 value = pixel[i];
  140. if (value > to)
  141. m_outRight.at(i)++;
  142. else if (value < from)
  143. m_outLeft.at(i)++;
  144. else
  145. m_bins.at(i).at(static_cast<TQ_UINT8>((value - from) * factor))++;
  146. }
  147. m_count++;
  148. }
  149. pixels += pSize;
  150. selectionMask++;
  151. nPixels--;
  152. }
  153. }
  154. else {
  155. while (nPixels > 0) {
  156. TQ_UINT16* pixel = reinterpret_cast<TQ_UINT16*>(pixels);
  157. if ( ! (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) {
  158. for (int i = 0; i < m_channels; i++) {
  159. TQ_UINT16 value = pixel[i];
  160. if (value > to)
  161. m_outRight.at(i)++;
  162. else if (value < from)
  163. m_outLeft.at(i)++;
  164. else
  165. m_bins.at(i).at(static_cast<TQ_UINT8>((value - from) * factor))++;
  166. }
  167. m_count++;
  168. }
  169. pixels += pSize;
  170. nPixels--;
  171. }
  172. }
  173. }
  174. // ------------ Float32 ---------------------
  175. KisBasicF32HistogramProducer::KisBasicF32HistogramProducer(const KisID& id, KisColorSpace *cs)
  176. : KisBasicHistogramProducer(id, cs->nChannels(), 256, cs)
  177. {
  178. }
  179. TQString KisBasicF32HistogramProducer::positionToString(double pos) const {
  180. return TQString("%1").arg(static_cast<float>(pos)); // XXX I doubt this is correct!
  181. }
  182. double KisBasicF32HistogramProducer::maximalZoom() const {
  183. // XXX What _is_ the maximal zoom here? I don't think there is one with floats, so this seems a fine compromis for the moment
  184. return 1.0 / 255.0;
  185. }
  186. void KisBasicF32HistogramProducer::addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *cs) {
  187. // The view
  188. float from = static_cast<float>(m_from);
  189. float width = static_cast<float>(m_width);
  190. float to = from + width;
  191. float factor = 255.0 / width;
  192. TQ_INT32 pSize = cs->pixelSize();
  193. if ( selectionMask ) {
  194. while (nPixels > 0) {
  195. float* pixel = reinterpret_cast<float*>(pixels);
  196. if ( !((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) {
  197. for (int i = 0; i < m_channels; i++) {
  198. float value = pixel[i];
  199. if (value > to)
  200. m_outRight.at(i)++;
  201. else if (value < from)
  202. m_outLeft.at(i)++;
  203. else
  204. m_bins.at(i).at(static_cast<TQ_UINT8>((value - from) * factor))++;
  205. }
  206. m_count++;
  207. }
  208. pixels += pSize;
  209. selectionMask++;
  210. nPixels--;
  211. }
  212. }
  213. else {
  214. while (nPixels > 0) {
  215. float* pixel = reinterpret_cast<float*>(pixels);
  216. if ( !(m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) {
  217. for (int i = 0; i < m_channels; i++) {
  218. float value = pixel[i];
  219. if (value > to)
  220. m_outRight.at(i)++;
  221. else if (value < from)
  222. m_outLeft.at(i)++;
  223. else
  224. m_bins.at(i).at(static_cast<TQ_UINT8>((value - from) * factor))++;
  225. }
  226. m_count++;
  227. }
  228. pixels += pSize;
  229. nPixels--;
  230. }
  231. }
  232. }
  233. #ifdef HAVE_OPENEXR
  234. // ------------ Float16 Half ---------------------
  235. KisBasicF16HalfHistogramProducer::KisBasicF16HalfHistogramProducer(const KisID& id,
  236. KisColorSpace *cs)
  237. : KisBasicHistogramProducer(id, cs->nChannels(), 256, cs) {
  238. }
  239. TQString KisBasicF16HalfHistogramProducer::positionToString(double pos) const {
  240. return TQString("%1").arg(static_cast<float>(pos)); // XXX I doubt this is correct!
  241. }
  242. double KisBasicF16HalfHistogramProducer::maximalZoom() const {
  243. // XXX What _is_ the maximal zoom here? I don't think there is one with floats, so this seems a fine compromis for the moment
  244. return 1.0 / 255.0;
  245. }
  246. void KisBasicF16HalfHistogramProducer::addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *cs) {
  247. // The view
  248. float from = static_cast<float>(m_from);
  249. float width = static_cast<float>(m_width);
  250. float to = from + width;
  251. float factor = 255.0 / width;
  252. TQ_INT32 pSize = cs->pixelSize();
  253. if ( selectionMask ) {
  254. while (nPixels > 0) {
  255. half* pixel = reinterpret_cast<half*>(pixels);
  256. if ( !((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) {
  257. for (int i = 0; i < m_channels; i++) {
  258. float value = pixel[i];
  259. if (value > to)
  260. m_outRight.at(i)++;
  261. else if (value < from)
  262. m_outLeft.at(i)++;
  263. else
  264. m_bins.at(i).at(static_cast<TQ_UINT8>((value - from) * factor))++;
  265. }
  266. m_count++;
  267. }
  268. pixels += pSize;
  269. selectionMask++;
  270. nPixels--;
  271. }
  272. }
  273. else {
  274. while (nPixels > 0) {
  275. half* pixel = reinterpret_cast<half*>(pixels);
  276. if ( !(m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) {
  277. for (int i = 0; i < m_channels; i++) {
  278. float value = pixel[i];
  279. if (value > to)
  280. m_outRight.at(i)++;
  281. else if (value < from)
  282. m_outLeft.at(i)++;
  283. else
  284. m_bins.at(i).at(static_cast<TQ_UINT8>((value - from) * factor))++;
  285. }
  286. m_count++;
  287. }
  288. pixels += pSize;
  289. nPixels--;
  290. }
  291. }
  292. }
  293. #endif
  294. // ------------ Generic RGB ---------------------
  295. KisGenericRGBHistogramProducer::KisGenericRGBHistogramProducer()
  296. : KisBasicHistogramProducer(KisID("GENRGBHISTO", i18n("Generic RGB Histogram")),
  297. 3, 256, 0) {
  298. /* we set 0 as colorspece, because we are not based on a specific colorspace. This
  299. is no problem for the superclass since we override channels() */
  300. m_channelsList.append(new KisChannelInfo(i18n("R"), i18n("R"), 0, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, TQColor(255,0,0)));
  301. m_channelsList.append(new KisChannelInfo(i18n("G"), i18n("G"), 1, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, TQColor(0,255,0)));
  302. m_channelsList.append(new KisChannelInfo(i18n("B"), i18n("B"), 2, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, TQColor(0,0,255)));
  303. }
  304. TQValueVector<KisChannelInfo *> KisGenericRGBHistogramProducer::channels() {
  305. return m_channelsList;
  306. }
  307. TQString KisGenericRGBHistogramProducer::positionToString(double pos) const {
  308. return TQString("%1").arg(static_cast<TQ_UINT8>(pos * UINT8_MAX));
  309. }
  310. double KisGenericRGBHistogramProducer::maximalZoom() const {
  311. return 1.0;
  312. }
  313. void KisGenericRGBHistogramProducer::addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *cs)
  314. {
  315. for (int i = 0; i < m_channels; i++) {
  316. m_outRight.at(i) = 0;
  317. m_outLeft.at(i) = 0;
  318. }
  319. TQColor c;
  320. TQ_INT32 pSize = cs->pixelSize();
  321. if (selectionMask) {
  322. while (nPixels > 0) {
  323. if ( !((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) {
  324. cs->toTQColor(pixels, &c);
  325. m_bins.at(0).at(c.red())++;
  326. m_bins.at(1).at(c.green())++;
  327. m_bins.at(2).at(c.blue())++;
  328. m_count++;
  329. }
  330. pixels += pSize;
  331. selectionMask++;
  332. nPixels--;
  333. }
  334. }
  335. else {
  336. while (nPixels > 0) {
  337. if ( !(m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) {
  338. cs->toTQColor(pixels, &c);
  339. m_bins.at(0).at(c.red())++;
  340. m_bins.at(1).at(c.green())++;
  341. m_bins.at(2).at(c.blue())++;
  342. m_count++;
  343. }
  344. pixels += pSize;
  345. nPixels--;
  346. }
  347. }
  348. }
  349. // ------------ Generic L*a*b* ---------------------
  350. KisGenericLabHistogramProducer::KisGenericLabHistogramProducer()
  351. : KisBasicHistogramProducer(KisID("GENLABHISTO", i18n("L*a*b* Histogram")), 3, 256, 0) {
  352. /* we set 0 as colorspace, because we are not based on a specific colorspace. This
  353. is no problem for the superclass since we override channels() */
  354. m_channelsList.append(new KisChannelInfo(i18n("L*"), i18n("L"), 0, KisChannelInfo::COLOR, KisChannelInfo::UINT8));
  355. m_channelsList.append(new KisChannelInfo(i18n("a*"), i18n("a"), 1, KisChannelInfo::COLOR, KisChannelInfo::UINT8));
  356. m_channelsList.append(new KisChannelInfo(i18n("b*"), i18n("b"), 2, KisChannelInfo::COLOR, KisChannelInfo::UINT8));
  357. if (!m_labCs) {
  358. KisProfile *labProfile = new KisProfile(cmsCreateLabProfile(NULL));
  359. m_labCs = new KisLabColorSpace(0, labProfile);
  360. }
  361. m_colorSpace = m_labCs;
  362. }
  363. KisGenericLabHistogramProducer::~KisGenericLabHistogramProducer()
  364. {
  365. delete m_channelsList[0];
  366. delete m_channelsList[1];
  367. delete m_channelsList[2];
  368. }
  369. TQValueVector<KisChannelInfo *> KisGenericLabHistogramProducer::channels() {
  370. return m_channelsList;
  371. }
  372. TQString KisGenericLabHistogramProducer::positionToString(double pos) const {
  373. return TQString("%1").arg(static_cast<TQ_UINT16>(pos * UINT16_MAX));
  374. }
  375. double KisGenericLabHistogramProducer::maximalZoom() const {
  376. return 1.0;
  377. }
  378. void KisGenericLabHistogramProducer::addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *cs)
  379. {
  380. for (int i = 0; i < m_channels; i++) {
  381. m_outRight.at(i) = 0;
  382. m_outLeft.at(i) = 0;
  383. }
  384. TQ_UINT8 dst[8];
  385. TQ_INT32 pSize = cs->pixelSize();
  386. if (selectionMask) {
  387. while (nPixels > 0) {
  388. if ( !((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) {
  389. /*
  390. cs->toTQColor(pixels, &c);
  391. m_bins.at(0).at(c.red())++;
  392. */
  393. m_count++;
  394. }
  395. pixels += pSize;
  396. selectionMask++;
  397. nPixels--;
  398. }
  399. }
  400. else {
  401. while (nPixels > 0) {
  402. if ( !(m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) {
  403. cs->convertPixelsTo(pixels, dst, m_colorSpace, 1);
  404. m_bins.at(0).at(m_colorSpace->scaleToU8(dst, 0))++;
  405. m_bins.at(1).at(m_colorSpace->scaleToU8(dst, 1))++;
  406. m_bins.at(2).at(m_colorSpace->scaleToU8(dst, 2))++;
  407. m_count++;
  408. }
  409. pixels += pSize;
  410. nPixels--;
  411. }
  412. }
  413. }