SMIL  1.0.4
DImageDraw.hpp
1 /*
2  * Copyright (c) 2011-2016, Matthieu FAESSEL and ARMINES
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of Matthieu FAESSEL, or ARMINES nor the
14  * names of its contributors may be used to endorse or promote products
15  * derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #ifndef _D_IMAGE_DRAW_HPP
31 #define _D_IMAGE_DRAW_HPP
32 
33 #include "DLineArith.hpp"
34 #include "Base/include/DImageDraw.h"
35 
36 #ifdef USE_FREETYPE
37 #include <ft2build.h>
38 #include FT_FREETYPE_H
39 #endif // USE_FREETYPE
40 
41 namespace smil
42 {
57  template <class T>
58  RES_T drawLine(Image<T> &im, int x0, int y0, int x1, int y1,
59  T value = ImDtTypes<T>::max())
60  {
61  if (!im.isAllocated())
62  return RES_ERR_BAD_ALLOCATION;
63 
64  size_t imW = im.getWidth();
65  size_t imH = im.getHeight();
66 
67  vector<IntPoint> bPoints;
68  if (x0 < 0 || x0 >= int(imW) || y0 < 0 || y0 >= int(imH) || x1 < 0 ||
69  x1 >= int(imW) || y1 < 0 || y1 >= int(imH)) {
70  bPoints = bresenhamPoints(x0, y0, x1, y1, imW, imH);
71  } else {
72  // no image range check (faster)
73  bPoints = bresenhamPoints(x0, y0, x1, y1);
74  }
75 
76  typename Image<T>::sliceType lines = im.getLines();
77 
78  for (vector<IntPoint>::iterator it = bPoints.begin(); it != bPoints.end();
79  it++)
80  lines[(*it).y][(*it).x] = value;
81 
82  im.modified();
83  return RES_OK;
84  }
85 
94  template <class T>
95  RES_T drawLine(Image<T> &imOut, vector<UINT> coords,
96  T value = ImDtTypes<T>::max())
97  {
98  if (coords.size() != 4)
99  return RES_ERR;
100  return drawLine<T>(imOut, coords[0], coords[1], coords[2], coords[3],
101  value);
102  }
103 
115  template <class T>
116  RES_T drawRectangle(Image<T> &imOut, int x0, int y0, size_t width,
117  size_t height, T value = ImDtTypes<T>::max(),
118  bool fill = false, size_t zSlice = 0)
119  {
120  ASSERT_ALLOCATED(&imOut);
121 
122  ImageFreezer freeze(imOut);
123 
124  size_t imW = imOut.getWidth();
125  size_t imH = imOut.getHeight();
126  size_t imD = imOut.getDepth();
127 
128  ASSERT((zSlice < imD), "zSlice is out of range", RES_ERR);
129 
130  size_t x1 = x0 + width - 1;
131  size_t y1 = y0 + height - 1;
132  x1 = x1 < imW ? x1 : imW - 1;
133  y1 = y1 < imH ? y1 : imH - 1;
134 
135  x0 = x0 >= 0 ? x0 : 0;
136  y0 = y0 >= 0 ? y0 : 0;
137 
138  typename Image<T>::volType slices = imOut.getSlices();
139  const typename Image<T>::sliceType lines = slices[zSlice];
140  fillLine<T> fillFunc;
141 
142  if (fill) {
143  for (size_t j = y0; j <= y1; j++)
144  fillFunc(lines[j] + x0, width, value);
145  } else {
146  fillFunc(lines[y0] + x0, width, value);
147  fillFunc(lines[y1] + x0, width, value);
148  for (size_t j = y0 + 1; j <= y1; j++) {
149  lines[j][x0] = value;
150  lines[j][x1] = value;
151  }
152  }
153 
154  return RES_OK;
155  }
156 
172  template <class T>
173  RES_T drawRectangle(Image<T> &imOut, vector<UINT> coords,
174  T value = ImDtTypes<T>::max(), bool fill = false)
175  {
176  if (coords.size() != 4)
177  return RES_ERR;
178  return drawRectangle<T>(imOut, coords[0], coords[1],
179  coords[2] - coords[0] + 1,
180  coords[3] - coords[1] + 1, value, fill);
181  }
182 
196  template <class T, class MapT>
197  RES_T drawRectangles(Image<T> &imOut,
198  const map<MapT, vector<size_t>> &coordsVectMap,
199  bool fill = false)
200  {
201  ASSERT_ALLOCATED(&imOut);
202  ImageFreezer freeze(imOut);
203 
204  typename map<MapT, vector<size_t>>::const_iterator it =
205  coordsVectMap.begin();
206  if (it->second.size() != 4)
207  return RES_ERR;
208  for (; it != coordsVectMap.end(); it++) {
209  const vector<size_t> &coords = it->second;
210  T val = T(it->first);
211  if (drawRectangle<T>(imOut, coords[0], coords[1],
212  coords[2] - coords[0] + 1, coords[3] - coords[1] + 1,
213  val, fill) != RES_OK) {
214  return RES_ERR;
215  }
216  }
217  return RES_OK;
218  }
219 
232  template <class T>
233  RES_T drawCircle(Image<T> &imOut, int x0, int y0, int radius,
234  T value = ImDtTypes<T>::max(), size_t zSlice = 0)
235  {
236  ASSERT_ALLOCATED(&imOut);
237  ASSERT((zSlice < imOut.getDepth()), "zSlice is out of range", RES_ERR);
238 
239  ImageFreezer freeze(imOut);
240 
241  int imW = imOut.getWidth();
242  int imH = imOut.getHeight();
243 
244  typename ImDtTypes<T>::sliceType lines = imOut.getSlices()[zSlice];
245 
246  int d = (5 - radius * 4) / 4;
247  int x = 0;
248  int y = radius;
249  // int ptX, ptY;
250 
251  do {
252  if (x0 + x >= 0 && x0 + x <= imW - 1 && y0 + y >= 0 && y0 + y <= imH - 1)
253  lines[y0 + y][x0 + x] = value;
254  if (x0 + x >= 0 && x0 + x <= imW - 1 && y0 - y >= 0 && y0 - y <= imH - 1)
255  lines[y0 - y][x0 + x] = value;
256  if (x0 - x >= 0 && x0 - x <= imW - 1 && y0 + y >= 0 && y0 + y <= imH - 1)
257  lines[y0 + y][x0 - x] = value;
258  if (x0 - x >= 0 && x0 - x <= imW - 1 && y0 - y >= 0 && y0 - y <= imH - 1)
259  lines[y0 - y][x0 - x] = value;
260  if (x0 + y >= 0 && x0 + y <= imW - 1 && y0 + x >= 0 && y0 + x <= imH - 1)
261  lines[y0 + x][x0 + y] = value;
262  if (x0 + y >= 0 && x0 + y <= imW - 1 && y0 - x >= 0 && y0 - x <= imH - 1)
263  lines[y0 - x][x0 + y] = value;
264  if (x0 - y >= 0 && x0 - y <= imW - 1 && y0 + x >= 0 && y0 + x <= imH - 1)
265  lines[y0 + x][x0 - y] = value;
266  if (x0 - y >= 0 && x0 - y <= imW - 1 && y0 - x >= 0 && y0 - x <= imH - 1)
267  lines[y0 - x][x0 - y] = value;
268  if (d < 0) {
269  d = d + (4 * x) + 6;
270  } else {
271  d = d + 4 * (x - y) + 10;
272  y--;
273  }
274  x++;
275  } while (x <= y);
276 
277  return RES_OK;
278  }
279 
288  template <class T>
289  RES_T drawSphere(Image<T> &imOut, int x0, int y0, int z0, int radius,
290  T value = ImDtTypes<T>::max())
291  {
292  ASSERT_ALLOCATED(&imOut);
293 
294  ImageFreezer freeze(imOut);
295 
296  int imW = imOut.getWidth();
297  int imH = imOut.getHeight();
298  int imD = imOut.getDepth();
299 
300  int x1 = MAX(x0 - radius, 0);
301  int y1 = MAX(y0 - radius, 0);
302  int z1 = MAX(z0 - radius, 0);
303 
304  int x2 = MIN(x0 + radius, imW - 1);
305  int y2 = MIN(y0 + radius, imH - 1);
306  int z2 = MIN(z0 + radius, imD - 1);
307 
308  int r2 = radius * radius;
309 
310  typename Image<T>::volType slices = imOut.getSlices();
311  typename Image<T>::sliceType lines;
312  typename Image<T>::lineType curLine;
313 
314  for (int z = z1; z <= z2; z++) {
315  lines = slices[z];
316  for (int y = y1; y <= y2; y++) {
317  curLine = lines[y];
318  for (int x = x1; x <= x2; x++)
319  if ((x - x0) * (x - x0) + (y - y0) * (y - y0) + (z - z0) * (z - z0) <=
320  r2)
321  curLine[x] = value;
322  }
323  }
324 
325  return RES_OK;
326  }
327 
339  template <class T>
340  RES_T drawDisc(Image<T> &imOut, int x0, int y0, size_t zSlice, int radius,
341  T value = ImDtTypes<T>::max())
342  {
343  ASSERT_ALLOCATED(&imOut);
344  ASSERT((zSlice < imOut.getDepth()), "zSlice is out of range", RES_ERR);
345 
346  ImageFreezer freeze(imOut);
347 
348  int imW = imOut.getWidth();
349  int imH = imOut.getHeight();
350 
351  int x1 = MAX(x0 - radius, 0);
352  int y1 = MAX(y0 - radius, 0);
353 
354  int x2 = MIN(x0 + radius, imW - 1);
355  int y2 = MIN(y0 + radius, imH - 1);
356 
357  int r2 = radius * radius;
358 
359  typename Image<T>::sliceType lines = imOut.getSlices()[zSlice];
360  typename Image<T>::lineType curLine;
361 
362  for (int y = y1; y <= y2; y++) {
363  curLine = lines[y];
364  for (int x = x1; x <= x2; x++)
365  if ((x - x0) * (x - x0) + (y - y0) * (y - y0) <= r2)
366  curLine[x] = value;
367  }
368 
369  return RES_OK;
370  }
371 
372  // 2D Overload
373  template <class T>
374  RES_T drawDisc(Image<T> &imOut, int x0, int y0, int radius,
375  T value = ImDtTypes<T>::max())
376  {
377  return drawDisc(imOut, x0, y0, 0, radius, value);
378  }
379 
390  template <class T>
391  RES_T drawBox(Image<T> &imOut, size_t x0, size_t y0, size_t z0, size_t width,
392  size_t height, size_t depth, T value = ImDtTypes<T>::max(),
393  bool fill = false)
394  {
395  ASSERT_ALLOCATED(&imOut);
396 
397  ImageFreezer freeze(imOut);
398 
399  ASSERT((drawRectangle(imOut, x0, y0, width, height, value, true, z0) ==
400  RES_OK));
401  for (size_t z = z0 + 1; z < z0 + depth - 1; z++)
402  ASSERT((drawRectangle(imOut, x0, y0, width, height, value, fill, z) ==
403  RES_OK));
404  ASSERT((drawRectangle(imOut, x0, y0, width, height, value, true,
405  z0 + depth - 1) == RES_OK));
406 
407  return RES_OK;
408  }
409 
410 #ifdef USE_FREETYPE
411 
417  template <class T>
418  RES_T drawText(Image<T> &imOut, size_t x, size_t y, size_t z, string txt,
419  string font, UINT size = 20, T value = ImDtTypes<T>::max())
420  {
421  ASSERT_ALLOCATED(&imOut);
422 
423  size_t imW = imOut.getWidth();
424  size_t imH = imOut.getHeight();
425 
426  ASSERT((x >= 0 && x < imW && y >= 0 && y < imH && z >= 0 &&
427  z < imOut.getDepth()),
428  "Text position out of image range.", RES_ERR);
429 
430  FT_Library library;
431  FT_Face face;
432  FT_GlyphSlot slot;
433  const char *text = txt.c_str();
434 
435  ASSERT((!FT_Init_FreeType(&library)),
436  "Problem initializing freetype library.", RES_ERR);
437  ASSERT((!FT_New_Face(library, font.c_str(), 0, &face)),
438  "The font file could not be opened.", RES_ERR);
439  ASSERT((!FT_Set_Pixel_Sizes(face, 0, size)), "Error defining font size.",
440  RES_ERR);
441 
442  slot = face->glyph;
443 
444  for (UINT c = 0; c < txt.length(); c++) {
445  FT_Load_Char(face, text[c],
446  FT_LOAD_NO_BITMAP | FT_LOAD_RENDER | FT_LOAD_TARGET_MONO);
447 
448  FT_Bitmap *bitmap = &slot->bitmap;
449 
450  FT_Int i, j, p, q;
451  FT_Int x_min = x + slot->bitmap_left;
452  FT_Int y_min = y - slot->bitmap_top;
453  FT_Int x_max = x_min + bitmap->width;
454  FT_Int y_max = y_min + bitmap->rows;
455 
456  typename ImDtTypes<T>::sliceType slc = imOut.getSlices()[z];
457 
458  for (j = y_min, q = 0; j < y_max; j++, q++) {
459  unsigned char *in = bitmap->buffer + q * bitmap->pitch;
460  typename ImDtTypes<T>::lineType out = slc[j];
461  unsigned char bit = 0x80;
462  for (i = x_min, p = 0; i < x_max; i++, p++) {
463  if (i >= 0 && j >= 0 && i < (int) imW && j < (int) imH)
464  if (*in & bit)
465  out[i] = value;
466  bit >>= 1;
467  if (bit == 0) {
468  bit = 0x80;
469  in++;
470  }
471  }
472  }
473  x += slot->advance.x >> 6;
474  y += slot->advance.y >> 6;
475  }
476 
477  FT_Done_Face(face);
478  FT_Done_FreeType(library);
479 
480  imOut.modified();
481 
482  return RES_OK;
483  }
484 
485  template <class T>
486  RES_T drawText(Image<T> &imOut, size_t x, size_t y, string txt, string font,
487  UINT size = 20, T value = ImDtTypes<T>::max())
488  {
489  return drawText(imOut, x, y, 0, txt, font, size, value);
490  }
491 
492 #endif // USE_FREETYPE
493 
513  // TODO Extend to 3D
514  template <class T>
515  RES_T copyPattern(const Image<T> &imIn, int x0, int y0, int width, int height,
516  Image<T> &imOut, int nbr_along_x, int nbr_along_y)
517  {
518  ASSERT_ALLOCATED(&imIn, &imOut)
519 
520  typename ImDtTypes<T>::sliceType linesIn = imIn.getSlices()[0];
521  typename ImDtTypes<T>::sliceType linesOut = imOut.getSlices()[0];
522 
523  size_t imSize[3];
524  imOut.getSize(imSize);
525 
526  int nX = min(int(ceil(double(imSize[0]) / width)), nbr_along_x);
527  int xPad = imSize[0] % width;
528  int nXfull = xPad == 0 ? nX : nX - 1;
529 
530  int nY = min(int(ceil(double(imSize[1]) / height)), nbr_along_y);
531  int yPad = imSize[1] % height;
532  int nYfull = yPad == 0 ? nY : nY - 1;
533 
534  size_t cpLen = nXfull * width + xPad;
535 
536 #ifdef USE_OPEN_MP
537  int nthreads = Core::getInstance()->getNumberOfThreads();
538 #pragma omp parallel num_threads(nthreads)
539 #endif // USE_OPEN_MP
540  {
541  // Copy along X
542 
543 #ifdef USE_OPEN_MP
544 #pragma omp for
545 #endif // USE_OPEN_MP
546  for (int j = 0; j < height; j++) {
547  typename ImDtTypes<T>::lineType lineIn = linesIn[y0 + j] + x0;
548  typename ImDtTypes<T>::lineType lineOut = linesOut[j];
549 
550  for (int i = 0; i < nXfull; i++) {
551  copyLine<T>(lineIn, width, lineOut);
552  lineOut += width;
553  }
554  copyLine<T>(lineIn, xPad, lineOut);
555  }
556 
557 #ifdef USE_OPEN_MP
558 #pragma omp barrier
559 #endif // USE_OPEN_MP
560 
561  // Copy along Y
562 
563  for (int n = 1; n < nYfull; n++) {
564 #ifdef USE_OPEN_MP
565 #pragma omp for
566 #endif // USE_OPEN_MP
567  for (int j = 0; j < height; j++) {
568  typename ImDtTypes<T>::lineType lineIn = linesOut[j];
569  typename ImDtTypes<T>::lineType lineOut = linesOut[n * height + j];
570 
571  copyLine<T>(lineIn, cpLen, lineOut);
572  }
573  }
574  for (int n = nYfull; n < nY; n++) {
575 #ifdef USE_OPEN_MP
576 #pragma omp for
577 #endif // USE_OPEN_MP
578  for (int j = 0; j < yPad; j++) {
579  typename ImDtTypes<T>::lineType lineIn = linesOut[j];
580  typename ImDtTypes<T>::lineType lineOut = linesOut[n * height + j];
581 
582  copyLine<T>(lineIn, cpLen, lineOut);
583  }
584  }
585  }
586 
587  return RES_OK;
588  }
589 
590  template <class T>
591  RES_T copyPattern(const Image<T> &imIn, int x0, int y0, int width, int height,
592  Image<T> &imOut)
593  {
594  return copyPattern(imIn, x0, y0, width, height, imOut,
595  numeric_limits<int>::max(), numeric_limits<int>::max());
596  }
597 
598  template <class T>
599  RES_T copyPattern(const Image<T> &imIn, Image<T> &imOut, int nbr_along_x,
600  int nbr_along_y)
601  {
602  return copyPattern(imIn, 0, 0, imIn.getWidth(), imIn.getHeight(), imOut,
603  nbr_along_x, nbr_along_y);
604  }
605 
606  template <class T> RES_T copyPattern(const Image<T> &imIn, Image<T> &imOut)
607  {
608  return copyPattern(imIn, 0, 0, imIn.getWidth(), imIn.getHeight(), imOut,
609  numeric_limits<int>::max(), numeric_limits<int>::max());
610  }
611 
614 } // namespace smil
615 
616 #endif // _D_IMAGE_DRAW_HPP
bool isAllocated() const
Check if the image is allocated.
Definition: DBaseImage.h:176
size_t getWidth() const
Get image width.
Definition: DBaseImage.h:80
size_t getHeight() const
Get image height.
Definition: DBaseImage.h:85
Definition: DBaseImage.h:386
Main Image class.
Definition: DImage.hpp:57
virtual void modified()
Trigger modified event (allows to force display update)
volType getSlices() const
Get an array containing the start offset of each slice.
Definition: DImage.hpp:117
sliceType getLines() const
Get an array containing the start offset of each line.
Definition: DImage.hpp:111
RES_T fill(Image< T > &imOut, const T &value)
fill() - Fill an image with a given value.
Definition: DImageArith.hpp:1456
RES_T drawRectangles(Image< T > &imOut, const map< MapT, vector< size_t >> &coordsVectMap, bool fill=false)
Draw a list of rectangles.
Definition: DImageDraw.hpp:197
vector< IntPoint > bresenhamPoints(int p1x, int p1y, int p2x, int p2y, int xMax=0, int yMax=0)
Find intermediate points forming a line between two end points, using the Bresenham Line Draw Algorit...
Definition: DImageDraw.h:62
RES_T copyPattern(const Image< T > &imIn, int x0, int y0, int width, int height, Image< T > &imOut, int nbr_along_x, int nbr_along_y)
Copy a given pattern (zone of input image) several times in an output image.
Definition: DImageDraw.hpp:515
RES_T drawSphere(Image< T > &imOut, int x0, int y0, int z0, int radius, T value=ImDtTypes< T >::max())
Draw a sphere.
Definition: DImageDraw.hpp:289
RES_T drawBox(Image< T > &imOut, size_t x0, size_t y0, size_t z0, size_t width, size_t height, size_t depth, T value=ImDtTypes< T >::max(), bool fill=false)
Draw a box (3D)
Definition: DImageDraw.hpp:391
RES_T drawDisc(Image< T > &imOut, int x0, int y0, size_t zSlice, int radius, T value=ImDtTypes< T >::max())
Draw a disc.
Definition: DImageDraw.hpp:340
RES_T drawLine(Image< T > &imOut, vector< UINT > coords, T value=ImDtTypes< T >::max())
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: DImageDraw.hpp:95
RES_T drawRectangle(Image< T > &imOut, vector< UINT > coords, T value=ImDtTypes< T >::max(), bool fill=false)
Draw a rectangle.
Definition: DImageDraw.hpp:173
RES_T drawCircle(Image< T > &imOut, int x0, int y0, int radius, T value=ImDtTypes< T >::max(), size_t zSlice=0)
Draw a circle.
Definition: DImageDraw.hpp:233
Definition: DTypes.hpp:88
Definition: DBaseImageOperations.hxx:39