gvloadimage_pango.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /*************************************************************************
  2. * Copyright (c) 2011 AT&T Intellectual Property
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the Eclipse Public License v1.0
  5. * which accompanies this distribution, and is available at
  6. * https://www.eclipse.org/legal/epl-v10.html
  7. *
  8. * Contributors: Details at https://graphviz.org
  9. *************************************************************************/
  10. #include "config.h"
  11. #include <stdbool.h>
  12. #include <stdint.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <gvc/gvplugin_loadimage.h>
  16. #include <gvc/gvio.h>
  17. #include <cairo.h>
  18. typedef enum {
  19. FORMAT_PNG_CAIRO, FORMAT_PNG_PS,
  20. } format_type;
  21. static cairo_status_t
  22. reader (void *closure, unsigned char *data, unsigned int length)
  23. {
  24. assert(closure);
  25. if (length == fread(data, 1, length, (FILE *)closure)
  26. || feof((FILE *)closure))
  27. return CAIRO_STATUS_SUCCESS;
  28. return CAIRO_STATUS_READ_ERROR;
  29. }
  30. static void cairo_freeimage(usershape_t *us)
  31. {
  32. cairo_surface_destroy(us->data);
  33. }
  34. static cairo_surface_t* cairo_loadimage(GVJ_t * job, usershape_t *us)
  35. {
  36. cairo_surface_t *surface = NULL; /* source surface */
  37. assert(job);
  38. assert(us);
  39. assert(us->name);
  40. assert(us->name[0]);
  41. if (us->data) {
  42. if (us->datafree == cairo_freeimage)
  43. surface = us->data; /* use cached data */
  44. else {
  45. us->datafree(us); /* free incompatible cache data */
  46. us->datafree = NULL;
  47. us->data = NULL;
  48. }
  49. }
  50. if (!surface) { /* read file into cache */
  51. if (!gvusershape_file_access(us))
  52. return NULL;
  53. assert(us->f);
  54. switch (us->type) {
  55. #ifdef CAIRO_HAS_PNG_FUNCTIONS
  56. case FT_PNG:
  57. surface = cairo_image_surface_create_from_png_stream(reader, us->f);
  58. cairo_surface_reference(surface);
  59. break;
  60. #endif
  61. default:
  62. surface = NULL;
  63. }
  64. if (surface) {
  65. us->data = surface;
  66. us->datafree = cairo_freeimage;
  67. }
  68. gvusershape_file_release(us);
  69. }
  70. return surface;
  71. }
  72. static void pango_loadimage_cairo(GVJ_t * job, usershape_t *us, boxf b, bool filled)
  73. {
  74. cairo_t *cr = job->context; /* target context */
  75. cairo_surface_t *surface; /* source surface */
  76. assert(job);
  77. assert(us);
  78. assert(us->name);
  79. assert(us->name[0]);
  80. // suppress unused parameter warning
  81. (void)filled;
  82. surface = cairo_loadimage(job, us);
  83. if (surface) {
  84. cairo_save(cr);
  85. cairo_translate(cr, b.LL.x, -b.UR.y);
  86. cairo_scale(cr, (b.UR.x - b.LL.x)/(us->w), (b.UR.y - b.LL.y)/(us->h));
  87. cairo_set_source_surface (cr, surface, 0, 0);
  88. cairo_paint (cr);
  89. cairo_restore(cr);
  90. }
  91. }
  92. static void pango_loadimage_ps(GVJ_t * job, usershape_t *us, boxf b, bool filled)
  93. {
  94. cairo_surface_t *surface; /* source surface */
  95. cairo_format_t format;
  96. int X, Y, x, y, stride;
  97. // suppress unused parameter warning
  98. (void)filled;
  99. surface = cairo_loadimage(job, us);
  100. if (surface) {
  101. format = cairo_image_surface_get_format(surface);
  102. if ((format != CAIRO_FORMAT_ARGB32) && (format != CAIRO_FORMAT_RGB24))
  103. return;
  104. X = cairo_image_surface_get_width(surface);
  105. Y = cairo_image_surface_get_height(surface);
  106. stride = cairo_image_surface_get_stride(surface);
  107. const unsigned char *data = cairo_image_surface_get_data(surface);
  108. gvputs(job, "save\n");
  109. /* define image data as string array (one per raster line) */
  110. /* see parallel code in gd_loadimage_ps(). FIXME: refactor... */
  111. gvputs(job, "/myctr 0 def\n");
  112. gvputs(job, "/myarray [\n");
  113. for (y = 0; y < Y; y++) {
  114. gvputs(job, "<");
  115. const unsigned char *ix = data + y * stride;
  116. for (x = 0; x < X; x++) {
  117. uint32_t rgba;
  118. memcpy(&rgba, ix, sizeof(rgba));
  119. ix += sizeof(rgba);
  120. const unsigned blue = rgba & 0xff;
  121. const unsigned green = (rgba >> 8) & 0xff;
  122. const unsigned red = (rgba >> 16) & 0xff;
  123. const unsigned alpha = (rgba >> 24) & 0xff;
  124. if (alpha < 0x7f)
  125. gvputs(job, "ffffff");
  126. else
  127. gvprintf(job, "%02x%02x%02x", red, green, blue);
  128. }
  129. gvputs(job, ">\n");
  130. }
  131. gvputs(job, "] def\n");
  132. gvputs(job,"/myproc { myarray myctr get /myctr myctr 1 add def } def\n");
  133. /* this sets the position of the image */
  134. gvprintf(job, "%g %g translate\n",
  135. (b.LL.x + (b.UR.x - b.LL.x) * (1. - (job->dpi.x) / 96.) / 2.),
  136. (b.LL.y + (b.UR.y - b.LL.y) * (1. - (job->dpi.y) / 96.) / 2.));
  137. /* this sets the rendered size to fit the box */
  138. gvprintf(job,"%g %g scale\n",
  139. ((b.UR.x - b.LL.x) * 72. / 96.),
  140. ((b.UR.y - b.LL.y) * 72. / 96.));
  141. /* xsize ysize bits-per-sample [matrix] */
  142. gvprintf(job, "%d %d 8 [%d 0 0 %d 0 %d]\n", X, Y, X, -Y, Y);
  143. gvputs(job, "{myproc} false 3 colorimage\n");
  144. gvputs(job, "restore\n");
  145. }
  146. }
  147. static gvloadimage_engine_t engine_cairo = {
  148. pango_loadimage_cairo
  149. };
  150. static gvloadimage_engine_t engine_ps = {
  151. pango_loadimage_ps
  152. };
  153. gvplugin_installed_t gvloadimage_pango_types[] = {
  154. {FORMAT_PNG_CAIRO, "png:cairo", 1, &engine_cairo, NULL},
  155. {FORMAT_PNG_PS, "png:lasi", 2, &engine_ps, NULL},
  156. {FORMAT_PNG_PS, "png:ps", 2, &engine_ps, NULL},
  157. {0, NULL, 0, NULL, NULL}
  158. };