Graphics-Potrace

 view release on metacpan or  search on metacpan

Potrace.xs  view on Meta::CPAN

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"

#include "potracelib.h"

#define ASSERT_SCALAR(sv,message) \
   if (sv == NULL) { \
      warn(message, __LINE__); \
      goto CLEAN_AND_LEAVE; \
   }

SV *_make_point(const potrace_dpoint_t *p) {
   AV *point = newAV();
   av_push(point, newSVnv(p->x));
   av_push(point, newSVnv(p->y));
   return newRV_noinc((SV *)point);
}

SV *_make_pathnode(potrace_path_t *node) {
   HV *retval = newHV();
   AV *curve  = newAV();
   unsigned int i;
   int tag;
   potrace_dpoint_t *c = NULL;
   HV *segment = NULL;
   HV *first_segment = NULL;
   SV *last_endpoint = NULL;
   
   hv_store(retval, "area", 4, newSViv(node->area), FALSE);
   hv_store(retval, "sign", 4, newSVpvn((node->sign == '-' ? "-" : "+"), 1), FALSE);
   hv_store(retval, "curve", 5, newRV_noinc((SV *)curve), FALSE);
   
   for (i = 0; i < (node->curve).n; ++i) {
      tag = (node->curve).tag[i];
      c   = (node->curve).c[i];

      segment = newHV();
      if (first_segment == NULL)
         first_segment = segment;

      if (last_endpoint) {
         hv_store(segment, "begin", 5, last_endpoint, FALSE);
         last_endpoint = NULL;
      }

      hv_store(segment, "end", 3, _make_point(c+2), FALSE);
      last_endpoint = _make_point(c+2); /* "begin" of the next segment */

      if (tag == POTRACE_CORNER) {
         hv_store(segment, "type", 4, newSVpvn("corner", 6), FALSE);
         hv_store(segment, "corner", 6, _make_point(c+1), FALSE);
      }
      else if (tag == POTRACE_CURVETO) {
         hv_store(segment, "type", 4, newSVpvn("bezier", 6), FALSE);
         hv_store(segment, "u", 1, _make_point(c), FALSE);
         hv_store(segment, "w", 1, _make_point(c+1), FALSE);
      }
      else {
         warn("Unknown tag: %d", tag);
         hv_store(segment, "type", 4, newSVpvn("unknown", 7), FALSE);
         hv_store(segment, "tag", 3, newSViv(tag), FALSE);
         hv_store(segment, "p1", 2, _make_point(c), FALSE);
         hv_store(segment, "p2", 2, _make_point(c+1), FALSE);
      }
      av_push(curve, newRV_noinc((SV *)segment));
   }
   if (last_endpoint)
      hv_store(first_segment, "begin", 5, last_endpoint, FALSE);
   
   return newRV_noinc((SV *)retval);
}

SV *_make_listpath(potrace_path_t *plist) {
   AV *retval = newAV();
   SV *node = NULL;
   unsigned int n = 0;

   while (plist != NULL) {
      node = _make_pathnode(plist);
      av_push(retval, node);
      plist = plist->next;
   }

   return newRV_noinc((SV *)retval);
}

SV *_make_treepath(potrace_path_t *plist) {
   AV *retval = newAV();
   SV *node = NULL;
   unsigned int n = 0;

   while (plist != NULL) {
      node = _make_pathnode(plist);
      hv_store((HV*)SvRV(node), "children", 8, _make_treepath(plist->childlist), FALSE);
      av_push(retval, node);
      plist = plist->sibling;
   }

   return newRV_noinc((SV *)retval);
}

void _progress_callback (double progress, void *data) {
   dSP;
   HV *handler = (HV *) SvRV((SV*) data);

   ENTER;
   SAVETMPS;

   PUSHMARK(SP);
   if (hv_exists(handler, "data", 4))
      XPUSHs(*hv_fetch(handler, "data", 4, FALSE));

   PUTBACK;

   call_sv(*hv_fetch(handler, "callback", 8, FALSE), G_DISCARD);

   FREETMPS;
   LEAVE;
}

int _set_progress (potrace_progress_t *target, SV *input) {
   SV *callback = input;
   HV *hash = NULL;
   SV *data = NULL;
   HV *handler = newHV();

   target->callback = _progress_callback;
   target->data = (void *) handler;



( run in 2.463 seconds using v1.01-cache-2.11-cpan-0bb4e1dffa6 )