KOffice – TDE office suite
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

407 linhas
12KB

  1. /*
  2. * Copyright (c) 2004 Michael Thaler <michael.thaler@physik.tu-muenchen.de>
  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 <math.h>
  19. #include <tqapplication.h>
  20. #include <tqwmatrix.h>
  21. #include <tqrect.h>
  22. #include <kdebug.h>
  23. #include <tdelocale.h>
  24. #include "kis_paint_device.h"
  25. #include "kis_rotate_visitor.h"
  26. #include "kis_progress_display_interface.h"
  27. #include "kis_iterators_pixel.h"
  28. #include "kis_selection.h"
  29. #include "kis_painter.h"
  30. void KisRotateVisitor::rotate(double angle, bool rotateAboutImageCentre, KisProgressDisplayInterface *progress)
  31. {
  32. KisPoint centreOfRotation;
  33. if (rotateAboutImageCentre) {
  34. centreOfRotation = KisPoint(m_dev->image()->width() / 2.0, m_dev->image()->height() / 2.0);
  35. } else {
  36. TQRect r = m_dev->exactBounds();
  37. centreOfRotation = KisPoint(r.x() + (r.width() / 2.0), r.y() + (r.height() / 2.0));
  38. }
  39. m_progress = progress;
  40. KisPaintDeviceSP rotated = rotate(m_dev, angle, centreOfRotation);
  41. if (!m_dev->hasSelection()) {
  42. // Clear everything
  43. m_dev->clear();
  44. } else {
  45. // Clear selected pixels
  46. m_dev->clearSelection();
  47. }
  48. KisPainter p(m_dev);
  49. TQRect r = rotated->extent();
  50. // OVER ipv COPY
  51. p.bitBlt(r.x(), r.y(), COMPOSITE_OVER, rotated, OPACITY_OPAQUE, r.x(), r.y(), r.width(), r.height());
  52. p.end();
  53. }
  54. void KisRotateVisitor::shear(double angleX, double angleY, KisProgressDisplayInterface *progress)
  55. {
  56. const double pi=3.1415926535897932385;
  57. double thetaX = angleX * pi / 180;
  58. double shearX = tan(thetaX);
  59. double thetaY = angleY * pi / 180;
  60. double shearY = tan(thetaY);
  61. TQRect r = m_dev->exactBounds();
  62. const int xShearSteps = r.height();
  63. const int yShearSteps = r.width();
  64. m_progress = progress;
  65. initProgress(xShearSteps + yShearSteps);
  66. KisPaintDeviceSP sheared;
  67. if (m_dev->hasSelection()) {
  68. sheared = new KisPaintDevice(m_dev->colorSpace(), "sheared");
  69. KisPainter p1(sheared);
  70. p1.bltSelection(r.x(), r.y(), COMPOSITE_OVER, m_dev, OPACITY_OPAQUE, r.x(), r.y(), r.width(), r.height());
  71. p1.end();
  72. sheared = xShear(sheared, shearX);
  73. }
  74. else {
  75. sheared = xShear(m_dev, shearX);
  76. }
  77. sheared = yShear(sheared, shearY);
  78. if (!m_dev->hasSelection()) {
  79. m_dev->clear();
  80. } else {
  81. // Clear selected pixels
  82. m_dev->clearSelection();
  83. }
  84. KisPainter p2(m_dev);
  85. r = sheared->extent();
  86. p2.bitBlt(r.x(), r.y(), COMPOSITE_OVER, sheared, OPACITY_OPAQUE, r.x(), r.y(), r.width(), r.height());
  87. p2.end();
  88. setProgressDone();
  89. }
  90. KisPaintDeviceSP KisRotateVisitor::rotateRight90(KisPaintDeviceSP src)
  91. {
  92. KisPaintDeviceSP dst = new KisPaintDevice(src->colorSpace(), "rotateright90");
  93. dst->setX(src->getX());
  94. dst->setY(src->getY());
  95. TQ_INT32 pixelSize = src->pixelSize();
  96. TQRect r = src->exactBounds();
  97. TQ_INT32 x = 0;
  98. for (TQ_INT32 y = r.bottom(); y >= r.top(); --y) {
  99. KisHLineIteratorPixel hit = src->createHLineIterator(r.x(), y, r.width(), false);
  100. KisVLineIterator vit = dst->createVLineIterator(-y, r.x(), r.width(), true);
  101. while (!hit.isDone()) {
  102. if (hit.isSelected()) {
  103. memcpy(vit.rawData(), hit.rawData(), pixelSize);
  104. }
  105. ++hit;
  106. ++vit;
  107. }
  108. ++x;
  109. incrementProgress();
  110. }
  111. return dst;
  112. }
  113. KisPaintDeviceSP KisRotateVisitor::rotateLeft90(KisPaintDeviceSP src)
  114. {
  115. KisPaintDeviceSP dst = new KisPaintDevice(src->colorSpace(), "rotateleft90");
  116. TQ_INT32 pixelSize = src->pixelSize();
  117. TQRect r = src->exactBounds();
  118. TQ_INT32 x = 0;
  119. for (TQ_INT32 y = r.top(); y <= r.bottom(); ++y) {
  120. // Read the horizontal line from back to front, write onto the vertical column
  121. KisHLineIteratorPixel hit = src->createHLineIterator(r.x(), y, r.width(), false);
  122. KisVLineIterator vit = dst->createVLineIterator(y, -r.x() - r.width(), r.width(), true);
  123. hit += r.width() - 1;
  124. while (!vit.isDone()) {
  125. if (hit.isSelected()) {
  126. memcpy(vit.rawData(), hit.rawData(), pixelSize);
  127. }
  128. --hit;
  129. ++vit;
  130. }
  131. ++x;
  132. incrementProgress();
  133. }
  134. return dst;
  135. }
  136. KisPaintDeviceSP KisRotateVisitor::rotate180(KisPaintDeviceSP src)
  137. {
  138. KisPaintDeviceSP dst = new KisPaintDevice(src->colorSpace(), "rotate180");
  139. dst->setX(src->getX());
  140. dst->setY(src->getY());
  141. TQ_INT32 pixelSize = src->pixelSize();
  142. TQRect r = src->exactBounds();
  143. for (TQ_INT32 y = r.top(); y <= r.bottom(); ++y) {
  144. KisHLineIteratorPixel srcIt = src->createHLineIterator(r.x(), y, r.width(), false);
  145. KisHLineIterator dstIt = dst->createHLineIterator( -r.x() - r.width(), -y, r.width(), true);
  146. srcIt += r.width() - 1;
  147. while (!dstIt.isDone()) {
  148. if (srcIt.isSelected()) {
  149. memcpy(dstIt.rawData(), srcIt.rawData(), pixelSize);
  150. }
  151. --srcIt;
  152. ++dstIt;
  153. }
  154. incrementProgress();
  155. }
  156. return dst;
  157. }
  158. KisPaintDeviceSP KisRotateVisitor::rotate(KisPaintDeviceSP src, double angle, KisPoint centreOfRotation)
  159. {
  160. const double pi = 3.1415926535897932385;
  161. if (angle >= 315 && angle < 360) {
  162. angle = angle - 360;
  163. } else if (angle > -360 && angle < -45) {
  164. angle = angle + 360;
  165. }
  166. TQRect r = src->exactBounds();
  167. const int xShearSteps = r.height();
  168. const int yShearSteps = r.width();
  169. const int fixedRotateSteps = r.height();
  170. KisPaintDeviceSP dst;
  171. if (angle == 90) {
  172. initProgress(fixedRotateSteps);
  173. dst = rotateRight90(src);
  174. } else if (angle == 180) {
  175. initProgress(fixedRotateSteps);
  176. dst = rotate180(src);
  177. } else if (angle == 270) {
  178. initProgress(fixedRotateSteps);
  179. dst = rotateLeft90(src);
  180. } else {
  181. double theta;
  182. if (angle >= -45 && angle < 45) {
  183. theta = angle * pi / 180;
  184. dst = src;
  185. initProgress(yShearSteps + (2 * xShearSteps));
  186. }
  187. else if (angle >= 45 && angle < 135) {
  188. initProgress(fixedRotateSteps + yShearSteps + (2 * xShearSteps));
  189. dst = rotateRight90(src);
  190. theta = (angle - 90) * pi / 180;
  191. }
  192. else if (angle >= 135 && angle < 225) {
  193. initProgress(fixedRotateSteps + yShearSteps + (2 * xShearSteps));
  194. dst = rotate180(src);
  195. theta = (angle - 180) * pi / 180;
  196. } else {
  197. initProgress(fixedRotateSteps + yShearSteps + (2 * xShearSteps));
  198. dst = rotateLeft90(src);
  199. theta = (angle - 270) * pi / 180;
  200. }
  201. double shearX = tan(theta / 2);
  202. double shearY = sin(theta);
  203. //first perform a shear along the x-axis by tan(theta/2)
  204. dst = xShear(dst, shearX);
  205. //next perform a shear along the y-axis by sin(theta)
  206. dst = yShear(dst, shearY);
  207. //again perform a shear along the x-axis by tan(theta/2)
  208. dst = xShear(dst, shearX);
  209. }
  210. double sinAngle = sin(angle * pi / 180);
  211. double cosAngle = cos(angle * pi / 180);
  212. KisPoint rotatedCentreOfRotation(
  213. centreOfRotation.x() * cosAngle - centreOfRotation.y() * sinAngle,
  214. centreOfRotation.x() * sinAngle + centreOfRotation.y() * cosAngle);
  215. dst->setX((TQ_INT32)(dst->getX() + centreOfRotation.x() - rotatedCentreOfRotation.x()));
  216. dst->setY((TQ_INT32)(dst->getY() + centreOfRotation.y() - rotatedCentreOfRotation.y()));
  217. setProgressDone();
  218. return dst;
  219. }
  220. KisPaintDeviceSP KisRotateVisitor::xShear(KisPaintDeviceSP src, double shearX)
  221. {
  222. KisPaintDeviceSP dst = new KisPaintDevice(src->colorSpace(), "xShear");
  223. dst->setX(src->getX());
  224. dst->setY(src->getY());
  225. TQRect r = src->exactBounds();
  226. double displacement;
  227. TQ_INT32 displacementInt;
  228. double weight;
  229. for (TQ_INT32 y = r.top(); y <= r.bottom(); y++) {
  230. //calculate displacement
  231. displacement = -y * shearX;
  232. displacementInt = (TQ_INT32)(floor(displacement));
  233. weight = displacement - displacementInt;
  234. TQ_UINT8 pixelWeights[2];
  235. pixelWeights[0] = static_cast<TQ_UINT8>(weight * 255 + 0.5);
  236. pixelWeights[1] = 255 - pixelWeights[0];
  237. KisHLineIteratorPixel srcIt = src->createHLineIterator(r.x(), y, r.width() + 1, false);
  238. KisHLineIteratorPixel leftSrcIt = src->createHLineIterator(r.x() - 1, y, r.width() + 1, false);
  239. KisHLineIteratorPixel dstIt = dst->createHLineIterator(r.x() + displacementInt, y, r.width() + 1, true);
  240. while (!srcIt.isDone()) {
  241. const TQ_UINT8 *pixelPtrs[2];
  242. pixelPtrs[0] = leftSrcIt.rawData();
  243. pixelPtrs[1] = srcIt.rawData();
  244. src->colorSpace()->mixColors(pixelPtrs, pixelWeights, 2, dstIt.rawData());
  245. ++srcIt;
  246. ++leftSrcIt;
  247. ++dstIt;
  248. }
  249. incrementProgress();
  250. }
  251. return dst;
  252. }
  253. KisPaintDeviceSP KisRotateVisitor::yShear(KisPaintDeviceSP src, double shearY)
  254. {
  255. KisPaintDeviceSP dst = new KisPaintDevice(src->colorSpace(), "yShear");
  256. dst->setX(src->getX());
  257. dst->setY(src->getY());
  258. TQRect r = src->exactBounds();
  259. double displacement;
  260. TQ_INT32 displacementInt;
  261. double weight;
  262. for (TQ_INT32 x = r.left(); x <= r.right(); x++) {
  263. //calculate displacement
  264. displacement = x * shearY;
  265. displacementInt = (TQ_INT32)(floor(displacement));
  266. weight = displacement - displacementInt;
  267. TQ_UINT8 pixelWeights[2];
  268. pixelWeights[0] = static_cast<TQ_UINT8>(weight * 255 + 0.5);
  269. pixelWeights[1] = 255 - pixelWeights[0];
  270. KisVLineIteratorPixel srcIt = src->createVLineIterator(x, r.y(), r.height() + 1, false);
  271. KisVLineIteratorPixel leftSrcIt = src->createVLineIterator(x, r.y() - 1, r.height() + 1, false);
  272. KisVLineIteratorPixel dstIt = dst->createVLineIterator(x, r.y() + displacementInt, r.height() + 1, true);
  273. while (!srcIt.isDone()) {
  274. const TQ_UINT8 *pixelPtrs[2];
  275. pixelPtrs[0] = leftSrcIt.rawData();
  276. pixelPtrs[1] = srcIt.rawData();
  277. src->colorSpace()->mixColors(pixelPtrs, pixelWeights, 2, dstIt.rawData());
  278. ++srcIt;
  279. ++leftSrcIt;
  280. ++dstIt;
  281. }
  282. incrementProgress();
  283. }
  284. return dst;
  285. }
  286. void KisRotateVisitor::initProgress(TQ_INT32 totalSteps)
  287. {
  288. if (!m_progress) return;
  289. m_progressTotalSteps = totalSteps;
  290. m_progressStep = 0;
  291. m_lastProgressPerCent = 0;
  292. m_progress->setSubject(this, true, false);
  293. emit notifyProgress(0);
  294. }
  295. void KisRotateVisitor::incrementProgress()
  296. {
  297. if (!m_progress) return;
  298. m_progressStep++;
  299. TQ_INT32 progressPerCent = (m_progressStep * 100) / m_progressTotalSteps;
  300. if (progressPerCent != m_lastProgressPerCent) {
  301. m_lastProgressPerCent = progressPerCent;
  302. emit notifyProgress(progressPerCent);
  303. }
  304. }
  305. void KisRotateVisitor::setProgressDone()
  306. {
  307. if (!m_progress) return;
  308. emit notifyProgressDone();
  309. }