raster.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. /*!
  2. \file lib/cairodriver/raster.c
  3. \brief GRASS cairo display driver - draw raster
  4. (C) 2007-2014 by Lars Ahlzen and the GRASS Development Team
  5. This program is free software under the GNU General Public License
  6. (>=v2). Read the file COPYING that comes with GRASS for details.
  7. \author Lars Ahlzen <lars ahlzen.com> (original contibutor)
  8. \author Glynn Clements
  9. */
  10. #include <math.h>
  11. #include "cairodriver.h"
  12. #include <grass/glocale.h>
  13. #define MAX_IMAGE_SIZE 32767
  14. #ifndef MIN
  15. #define MIN(a,b) ((a)<(b)?(a):(b))
  16. #endif
  17. #ifndef MAX
  18. #define MAX(a,b) ((a)>(b)?(a):(b))
  19. #endif
  20. static int src_t, src_b, src_l, src_r, src_w, src_h;
  21. static int dst_t, dst_b, dst_l, dst_r, dst_w, dst_h;
  22. static int *trans;
  23. static cairo_surface_t *src_surf;
  24. static unsigned char *src_data;
  25. static int src_stride, ca_row;
  26. static int masked;
  27. static double scale(double k, int src_0, int src_1, int dst_0, int dst_1)
  28. {
  29. return dst_0 + (double) (k - src_0) * (dst_1 - dst_0) / (src_1 - src_0);
  30. }
  31. static int scale_fwd_y(int sy)
  32. {
  33. return (int)floor(scale(sy, src_t, src_b, dst_t, dst_b) + 0.5);
  34. }
  35. static int scale_rev_x(int dx)
  36. {
  37. return (int)floor(scale(dx + 0.5, dst_l, dst_r, src_l, src_r));
  38. }
  39. static int next_row(int sy, int dy)
  40. {
  41. sy++;
  42. for (;;) {
  43. int y = scale_fwd_y(sy);
  44. if (y > dy)
  45. return sy - 1;
  46. sy++;
  47. }
  48. }
  49. /*!
  50. \brief Start drawing raster
  51. \todo are top and left swapped?
  52. \param mask non-zero int for mask
  53. \param s source (map) extent (left, right, top, bottom)
  54. \param d destination (image) extent (left, right, top, bottom)
  55. */
  56. void Cairo_begin_raster(int mask, int s[2][2], double d[2][2])
  57. {
  58. int i;
  59. cairo_status_t status;
  60. masked = mask;
  61. src_l = s[0][0];
  62. src_r = s[0][1];
  63. src_t = s[1][0];
  64. src_b = s[1][1];
  65. src_w = src_r - src_l;
  66. src_h = src_b - src_t;
  67. dst_l = (int) floor(d[0][0] + 0.5);
  68. dst_r = (int) floor(d[0][1] + 0.5);
  69. dst_t = (int) floor(d[1][0] + 0.5);
  70. dst_b = (int) floor(d[1][1] + 0.5);
  71. dst_w = dst_r - dst_l;
  72. dst_h = dst_b - dst_t;
  73. G_debug(1, "Cairo_begin_raster(): masked=%d, src_lrtb=%d %d %d %d -> w/h=%d %d, "
  74. "dst_lrtb=%d %d %d %d -> w/h=%d %d",
  75. masked, src_l, src_r, src_t, src_b, src_w, src_h,
  76. dst_l, dst_r, dst_t, dst_b, dst_w, dst_h);
  77. /* create source surface */
  78. src_surf = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, ca.width, ca.height);
  79. status = cairo_surface_status(src_surf);
  80. if (status != CAIRO_STATUS_SUCCESS)
  81. G_fatal_error("%s - %s - size: %dx%d (cairo limit: %dx%d)",
  82. _("Failed to create cairo surface"),
  83. cairo_status_to_string (status), ca.width, ca.height,
  84. MAX_IMAGE_SIZE, MAX_IMAGE_SIZE);
  85. src_data = cairo_image_surface_get_data(src_surf);
  86. src_stride = cairo_image_surface_get_stride(src_surf);
  87. ca_row = 0;
  88. /* allocate buffer for down-sampling data */
  89. trans = G_malloc(dst_w * sizeof(int));
  90. for (i = 0; i < dst_w; i++)
  91. trans[i] = scale_rev_x(dst_l + i);
  92. }
  93. /*!
  94. \brief Draw raster row
  95. \param n number of cells
  96. \param row raster row (starting at 0)
  97. \param red,grn,blu,nul red,green,blue and null value
  98. \return next row
  99. */
  100. int Cairo_raster(int n, int row,
  101. const unsigned char *red, const unsigned char *grn,
  102. const unsigned char *blu, const unsigned char *nul)
  103. {
  104. int d_y0 = scale_fwd_y(row + 0);
  105. int d_y1 = scale_fwd_y(row + 1);
  106. int d_rows = d_y1 - d_y0;
  107. int x0 = MAX(0 - dst_l, 0);
  108. int x1 = MIN(ca.width - dst_l, dst_w);
  109. int y0 = MAX(0 - d_y0, 0);
  110. int y1 = MIN(ca.height - d_y0, d_rows);
  111. int x, y;
  112. if (y1 <= y0)
  113. return next_row(row, d_y1);
  114. G_debug(3, "Cairo_raster(): n=%d row=%d", n, row);
  115. for (x = x0; x < x1; x++) {
  116. int xx = dst_l + x;
  117. int j = trans[x];
  118. unsigned int c;
  119. if (masked && nul && nul[j])
  120. c = 0;
  121. else {
  122. unsigned int r = red[j];
  123. unsigned int g = grn[j];
  124. unsigned int b = blu[j];
  125. unsigned int a = 0xFF;
  126. c = (a << 24) + (r << 16) + (g << 8) + (b << 0);
  127. }
  128. for (y = y0; y < y1; y++) {
  129. int yy = d_y0 + y;
  130. *(unsigned int *)(src_data + yy * src_stride + xx * 4) = c;
  131. }
  132. }
  133. ca.modified = 1;
  134. ca_row++;
  135. return next_row(row, d_y1);
  136. }
  137. /*!
  138. \brief Finish drawing raster
  139. */
  140. void Cairo_end_raster(void)
  141. {
  142. G_debug(1, "Cairo_end_raster()");
  143. /* paint source surface onto destination (scaled) */
  144. cairo_save(cairo);
  145. /* cairo_translate(cairo, dst_l, dst_t); */
  146. /* cairo_scale(cairo, dst_w / src_w, dst_h / src_h); */
  147. cairo_surface_mark_dirty(src_surf);
  148. cairo_set_source_surface(cairo, src_surf, 0, 0);
  149. cairo_pattern_set_filter(cairo_get_source(cairo), CAIRO_FILTER_NEAREST);
  150. cairo_paint(cairo);
  151. cairo_restore(cairo);
  152. /* cleanup */
  153. G_free(trans);
  154. cairo_surface_destroy(src_surf);
  155. ca.modified = 1;
  156. }