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.

289 lines
7.0 KiB

  1. /* Copyright (C) 2001-2017 Peter Selinger.
  2. * This file is part of Potrace. It is free software and it is covered
  3. * by the GNU General Public License. See the file COPYING for details. */
  4. #ifndef BITMAP_H
  5. #define BITMAP_H
  6. #include <errno.h>
  7. #include <stddef.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. /* The bitmap type is defined in potracelib.h */
  11. #include "potracelib.h"
  12. /* The present file defines some convenient macros and static inline
  13. * functions for accessing bitmaps. Since they only produce inline
  14. * code, they can be conveniently shared by the library and frontends,
  15. * if desired */
  16. /* ---------------------------------------------------------------------- */
  17. /* some measurements */
  18. #define BM_WORDSIZE ( (int) sizeof( potrace_word ) )
  19. #define BM_WORDBITS ( 8 * BM_WORDSIZE )
  20. #define BM_HIBIT ( ( (potrace_word) 1 ) << ( BM_WORDBITS - 1 ) )
  21. #define BM_ALLBITS ( ~(potrace_word) 0 )
  22. /* macros for accessing pixel at index (x,y). U* macros omit the
  23. * bounds check. */
  24. #define bm_scanline( bm, y ) ( ( bm )->map + (ptrdiff_t) ( y ) * (ptrdiff_t) ( bm )->dy )
  25. #define bm_index( bm, x, y ) ( &bm_scanline( bm, y )[( x ) / BM_WORDBITS] )
  26. #define bm_mask( x ) ( BM_HIBIT >> ( ( x ) & ( BM_WORDBITS - 1 ) ) )
  27. #define bm_range( x, a ) ( (int) ( x ) >= 0 && (int) ( x ) < ( a ) )
  28. #define bm_safe( bm, x, y ) ( bm_range( x, ( bm )->w ) && bm_range( y, ( bm )->h ) )
  29. #define BM_UGET( bm, x, y ) ( ( *bm_index( bm, x, y ) & bm_mask( x ) ) != 0 )
  30. #define BM_USET( bm, x, y ) ( *bm_index( bm, x, y ) |= bm_mask( x ) )
  31. #define BM_UCLR( bm, x, y ) ( *bm_index( bm, x, y ) &= ~bm_mask( x ) )
  32. #define BM_UINV( bm, x, y ) ( *bm_index( bm, x, y ) ^= bm_mask( x ) )
  33. #define BM_UPUT( bm, x, y, b ) ( ( b ) ? BM_USET( bm, x, y ) : BM_UCLR( bm, x, y ) )
  34. #define BM_GET( bm, x, y ) ( bm_safe( bm, x, y ) ? BM_UGET( bm, x, y ) : 0 )
  35. #define BM_SET( bm, x, y ) ( bm_safe( bm, x, y ) ? BM_USET( bm, x, y ) : 0 )
  36. #define BM_CLR( bm, x, y ) ( bm_safe( bm, x, y ) ? BM_UCLR( bm, x, y ) : 0 )
  37. #define BM_INV( bm, x, y ) ( bm_safe( bm, x, y ) ? BM_UINV( bm, x, y ) : 0 )
  38. #define BM_PUT( bm, x, y, b ) ( bm_safe( bm, x, y ) ? BM_UPUT( bm, x, y, b ) : 0 )
  39. /* calculate the size, in bytes, required for the data area of a
  40. * bitmap of the given dy and h. Assume h >= 0. Return -1 if the size
  41. * does not fit into the ptrdiff_t type. */
  42. static inline ptrdiff_t getsize( int dy, int h )
  43. {
  44. ptrdiff_t size;
  45. if( dy < 0 )
  46. {
  47. dy = -dy;
  48. }
  49. size = (ptrdiff_t) dy * (ptrdiff_t) h * (ptrdiff_t) BM_WORDSIZE;
  50. /* check for overflow error */
  51. if( size < 0 || ( h != 0 && dy != 0 && size / h / dy != BM_WORDSIZE ) )
  52. {
  53. return -1;
  54. }
  55. return size;
  56. }
  57. /* return the size, in bytes, of the data area of the bitmap. Return
  58. * -1 if the size does not fit into the ptrdiff_t type; however, this
  59. * cannot happen if the bitmap is well-formed, i.e., if created with
  60. * bm_new or bm_dup. */
  61. static inline ptrdiff_t bm_size( const potrace_bitmap_t* bm )
  62. {
  63. return getsize( bm->dy, bm->h );
  64. }
  65. /* calculate the base address of the bitmap data. Assume that the
  66. * bitmap is well-formed, i.e., its size fits into the ptrdiff_t type.
  67. * This is the case if created with bm_new or bm_dup. The base address
  68. * may differ from bm->map if dy is negative */
  69. static inline potrace_word* bm_base( const potrace_bitmap_t* bm )
  70. {
  71. int dy = bm->dy;
  72. if( dy >= 0 || bm->h == 0 )
  73. {
  74. return bm->map;
  75. }
  76. else
  77. {
  78. return bm_scanline( bm, bm->h - 1 );
  79. }
  80. }
  81. /* free the given bitmap. Leaves errno untouched. */
  82. static inline void bm_free( potrace_bitmap_t* bm )
  83. {
  84. if( bm && bm->map )
  85. {
  86. free( bm_base( bm ) );
  87. }
  88. free( bm );
  89. }
  90. /* return new bitmap initialized to 0. NULL with errno on error.
  91. * Assumes w, h >= 0. */
  92. static inline potrace_bitmap_t* bm_new( int w, int h )
  93. {
  94. potrace_bitmap_t* bm;
  95. int dy = w == 0 ? 0 : ( w - 1 ) / BM_WORDBITS + 1;
  96. ptrdiff_t size;
  97. size = getsize( dy, h );
  98. if( size < 0 )
  99. {
  100. errno = ENOMEM;
  101. return NULL;
  102. }
  103. if( size == 0 )
  104. {
  105. size = 1; /* make sure calloc() doesn't return NULL */
  106. }
  107. bm = (potrace_bitmap_t*) malloc( sizeof( potrace_bitmap_t ) );
  108. if( !bm )
  109. {
  110. return NULL;
  111. }
  112. bm->w = w;
  113. bm->h = h;
  114. bm->dy = dy;
  115. bm->map = (potrace_word*) calloc( 1, size );
  116. if( !bm->map )
  117. {
  118. free( bm );
  119. return NULL;
  120. }
  121. return bm;
  122. }
  123. /* clear the given bitmap. Set all bits to c. Assumes a well-formed
  124. * bitmap. */
  125. static inline void bm_clear( potrace_bitmap_t* bm, int c )
  126. {
  127. /* Note: if the bitmap was created with bm_new, then it is
  128. * guaranteed that size will fit into the ptrdiff_t type. */
  129. ptrdiff_t size = bm_size( bm );
  130. memset( bm_base( bm ), c ? -1 : 0, size );
  131. }
  132. /* duplicate the given bitmap. Return NULL on error with errno
  133. * set. Assumes a well-formed bitmap. */
  134. static inline potrace_bitmap_t* bm_dup( const potrace_bitmap_t* bm )
  135. {
  136. potrace_bitmap_t* bm1 = bm_new( bm->w, bm->h );
  137. int y;
  138. if( !bm1 )
  139. {
  140. return NULL;
  141. }
  142. for( y = 0; y < bm->h; y++ )
  143. {
  144. memcpy( bm_scanline( bm1, y ), bm_scanline( bm, y ),
  145. (size_t) bm1->dy * (size_t) BM_WORDSIZE );
  146. }
  147. return bm1;
  148. }
  149. /* invert the given bitmap. */
  150. static inline void bm_invert( potrace_bitmap_t* bm )
  151. {
  152. int dy = bm->dy;
  153. int y;
  154. int i;
  155. potrace_word* p;
  156. if( dy < 0 )
  157. {
  158. dy = -dy;
  159. }
  160. for( y = 0; y < bm->h; y++ )
  161. {
  162. p = bm_scanline( bm, y );
  163. for( i = 0; i < dy; i++ )
  164. {
  165. p[i] ^= BM_ALLBITS;
  166. }
  167. }
  168. }
  169. /* turn the given bitmap upside down. This does not move the bitmap
  170. * data or change the bm_base() address. */
  171. static inline void bm_flip( potrace_bitmap_t* bm )
  172. {
  173. int dy = bm->dy;
  174. if( bm->h == 0 || bm->h == 1 )
  175. {
  176. return;
  177. }
  178. bm->map = bm_scanline( bm, bm->h - 1 );
  179. bm->dy = -dy;
  180. }
  181. /* resize the bitmap to the given new height. The bitmap data remains
  182. * bottom-aligned (truncated at the top) when dy >= 0 and top-aligned
  183. * (truncated at the bottom) when dy < 0. Return 0 on success, or 1 on
  184. * error with errno set. If the new height is <= the old one, no error
  185. * should occur. If the new height is larger, the additional bitmap
  186. * data is *not* initialized. */
  187. static inline int bm_resize( potrace_bitmap_t* bm, int h )
  188. {
  189. int dy = bm->dy;
  190. ptrdiff_t newsize;
  191. potrace_word* newmap;
  192. if( dy < 0 )
  193. {
  194. bm_flip( bm );
  195. }
  196. newsize = getsize( dy, h );
  197. if( newsize < 0 )
  198. {
  199. errno = ENOMEM;
  200. goto error;
  201. }
  202. if( newsize == 0 )
  203. {
  204. newsize = 1; /* make sure realloc() doesn't return NULL */
  205. }
  206. newmap = (potrace_word*) realloc( bm->map, newsize );
  207. if( newmap == NULL )
  208. {
  209. goto error;
  210. }
  211. bm->map = newmap;
  212. bm->h = h;
  213. if( dy < 0 )
  214. {
  215. bm_flip( bm );
  216. }
  217. return 0;
  218. error:
  219. if( dy < 0 )
  220. {
  221. bm_flip( bm );
  222. }
  223. return 1;
  224. }
  225. #endif /* BITMAP_H */