int preloadSymbol(symbolSetObj *symbolset, symbolObj *symbol, rendererVTableObj *renderer) { switch(symbol->type) { case MS_SYMBOL_VECTOR: case MS_SYMBOL_ELLIPSE: case MS_SYMBOL_SIMPLE: case (MS_SYMBOL_TRUETYPE): break; case (MS_SYMBOL_SVG): #if defined(USE_SVG_CAIRO) || defined(USE_RSVG) return msPreloadSVGSymbol(symbol); #else msSetError(MS_SYMERR, "SVG symbol support is not enabled.", "preloadSymbol()"); return MS_FAILURE; #endif break; case (MS_SYMBOL_PIXMAP): { if(!symbol->pixmap_buffer) { if(MS_SUCCESS != msPreloadImageSymbol(renderer,symbol)) return MS_FAILURE; } } break; default: msSetError(MS_MISCERR,"unsupported symbol type %d", "preloadSymbol()", symbol->type); return MS_FAILURE; } return MS_SUCCESS; }
int renderSVGSymbolCairo(imageObj *img, double x, double y, symbolObj *symbol, symbolStyleObj *style) { #ifdef USE_SVG_CAIRO cairo_renderer *r = CAIRO_RENDERER(img); //double ox=symbol->sizex*0.5,oy=symbol->sizey*0.5; svg_cairo_status_t status; struct svg_symbol_cache *cache; msPreloadSVGSymbol(symbol); assert(symbol->renderer_cache); cache = symbol->renderer_cache; cairo_save(r->cr); cairo_translate(r->cr,x,y); cairo_scale(r->cr,style->scale,style->scale); if (style->rotation != 0) { cairo_rotate(r->cr, -style->rotation); cairo_translate (r->cr, -(int)(symbol->sizex/2), -(int)(symbol->sizey/2)); } else cairo_translate (r->cr, -(int)(symbol->sizex/2), -(int)(symbol->sizey/2)); status = svg_cairo_render(cache->svgc, r->cr); cairo_restore(r->cr); return MS_SUCCESS; #else msSetError(MS_MISCERR, "SVG Symbols requested but is not built with libsvgcairo", "renderSVGSymbolCairo()"); return MS_FAILURE; #endif }
int msRenderRasterizedSVGSymbol(imageObj *img, double x, double y, symbolObj *symbol, symbolStyleObj *style) { #if defined(USE_SVG_CAIRO) || defined(USE_RSVG) struct svg_symbol_cache *svg_cache; symbolStyleObj pixstyle; symbolObj pixsymbol; int status; if(MS_SUCCESS != msPreloadSVGSymbol(symbol)) return MS_FAILURE; svg_cache = (struct svg_symbol_cache*) symbol->renderer_cache; //already rendered at the right size and scale? return if(svg_cache->scale != style->scale || svg_cache->rotation != style->rotation) { cairo_t *cr; cairo_surface_t *surface; unsigned char *pb; int width, height, surface_w, surface_h; /* need to recompute the pixmap */ if(svg_cache->pixmap_buffer) { msFreeRasterBuffer(svg_cache->pixmap_buffer); } else { svg_cache->pixmap_buffer = msSmallCalloc(1,sizeof(rasterBufferObj)); } //increase pixmap size to accomodate scaling/rotation if (style->scale != 1.0) { width = surface_w = (symbol->sizex * style->scale + 0.5); height = surface_h = (symbol->sizey * style->scale + 0.5); } else { width = surface_w = symbol->sizex; height = surface_h = symbol->sizey; } if (style->rotation != 0) { surface_w = surface_h = MS_NINT(MS_MAX(height, width) * 1.415); } surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, surface_w, surface_h); cr = cairo_create(surface); if (style->rotation != 0) { cairo_translate(cr, surface_w / 2, surface_h / 2); cairo_rotate(cr, -style->rotation); cairo_translate(cr, -width / 2, -height / 2); } if (style->scale != 1.0) { cairo_scale(cr, style->scale, style->scale); } #ifdef USE_SVG_CAIRO if(svg_cairo_render(svg_cache->svgc, cr) != SVG_CAIRO_STATUS_SUCCESS) { return MS_FAILURE; } #else rsvg_handle_render_cairo(svg_cache->svgc, cr); #endif pb = cairo_image_surface_get_data(surface); //set up raster initializeRasterBufferCairo(svg_cache->pixmap_buffer, surface_w, surface_h, 0); memcpy(svg_cache->pixmap_buffer->data.rgba.pixels, pb, surface_w * surface_h * 4 * sizeof (unsigned char)); svg_cache->scale = style->scale; svg_cache->rotation = style->rotation; cairo_destroy(cr); cairo_surface_destroy(surface); } assert(svg_cache->pixmap_buffer->height && svg_cache->pixmap_buffer->width); pixstyle = *style; pixstyle.rotation = 0.0; pixstyle.scale = 1.0; pixsymbol.pixmap_buffer = svg_cache->pixmap_buffer; pixsymbol.type = MS_SYMBOL_PIXMAP; status = MS_IMAGE_RENDERER(img)->renderPixmapSymbol(img,x,y,&pixsymbol,&pixstyle); MS_IMAGE_RENDERER(img)->freeSymbol(&pixsymbol); return status; #else msSetError(MS_MISCERR, "SVG Symbols requested but MapServer is not built with libsvgcairo", "renderSVGSymbolCairo()"); return MS_FAILURE; #endif }
imageObj *getTile(imageObj *img, symbolObj *symbol, symbolStyleObj *s, int width, int height, int seamlessmode) { tileCacheObj *tile; int status = MS_SUCCESS; rendererVTableObj *renderer = img->format->vtable; if(width==-1 || height == -1) { width=height=MS_MAX(symbol->sizex,symbol->sizey); } tile = searchTileCache(img,symbol,s,width,height); if(tile==NULL) { imageObj *tileimg; double p_x,p_y; tileimg = msImageCreate(width,height,img->format,NULL,NULL,img->resolution, img->resolution, NULL); if(UNLIKELY(!tileimg)) { return NULL; } if(!seamlessmode) { p_x = width/2.0; p_y = height/2.0; switch(symbol->type) { case (MS_SYMBOL_TRUETYPE): { unsigned int unicode; glyph_element *glyphc; face_element *face = msGetFontFace(symbol->font, &img->map->fontset); if(UNLIKELY(!face)) { status = MS_FAILURE; break; } msUTF8ToUniChar(symbol->character, &unicode); unicode = msGetGlyphIndex(face,unicode); glyphc = msGetGlyphByIndex(face, s->scale, unicode); if(UNLIKELY(!face)) { status = MS_FAILURE; break; } status = drawGlyphMarker(tileimg, face, glyphc, p_x, p_y, s->scale, s->rotation, s->color, s->outlinecolor, s->outlinewidth); } break; case (MS_SYMBOL_PIXMAP): status = msPreloadImageSymbol(renderer,symbol); if(UNLIKELY(status == MS_FAILURE)) { break; } status = renderer->renderPixmapSymbol(tileimg, p_x, p_y, symbol, s); break; case (MS_SYMBOL_ELLIPSE): status = renderer->renderEllipseSymbol(tileimg, p_x, p_y,symbol, s); break; case (MS_SYMBOL_VECTOR): status = renderer->renderVectorSymbol(tileimg, p_x, p_y, symbol, s); break; case (MS_SYMBOL_SVG): #if defined(USE_SVG_CAIRO) || defined(USE_RSVG) status = msPreloadSVGSymbol(symbol); if(LIKELY(status == MS_SUCCESS)) { if (renderer->supports_svg) { status = renderer->renderSVGSymbol(tileimg, p_x, p_y, symbol, s); } else { status = msRenderRasterizedSVGSymbol(tileimg,p_x,p_y,symbol, s); } } #else msSetError(MS_SYMERR, "SVG symbol support is not enabled.", "getTile()"); status = MS_FAILURE; #endif break; default: msSetError(MS_SYMERR, "Unknown symbol type %d", "getTile()", symbol->type); status = MS_FAILURE; break; } if(UNLIKELY(status == MS_FAILURE)) { msFreeImage(tileimg); return NULL; } } else { /* * in seamless mode, we render the the symbol 9 times on a 3x3 grid to account for * antialiasing blending from one tile to the next. We finally keep the center tile */ imageObj *tile3img = msImageCreate(width*3,height*3,img->format,NULL,NULL, img->resolution, img->resolution, NULL); int i,j; rasterBufferObj tmpraster; for(i=1; i<=3; i++) { p_x = (i+0.5)*width; for(j=1; j<=3; j++) { p_y = (j+0.5) * height; switch(symbol->type) { case (MS_SYMBOL_TRUETYPE): { unsigned int unicode; glyph_element *glyphc; face_element *face = msGetFontFace(symbol->font, &img->map->fontset); if(UNLIKELY(!face)) { status = MS_FAILURE; break; } msUTF8ToUniChar(symbol->character, &unicode); unicode = msGetGlyphIndex(face,unicode); glyphc = msGetGlyphByIndex(face, s->scale, unicode); if(UNLIKELY(!glyphc)) { status = MS_FAILURE; break; } status = drawGlyphMarker(tileimg, face, glyphc, p_x, p_y, s->scale, s->rotation, s->color, s->outlinecolor, s->outlinewidth); } break; case (MS_SYMBOL_PIXMAP): status = msPreloadImageSymbol(renderer,symbol); if(UNLIKELY(status == MS_FAILURE)) { break; } status = renderer->renderPixmapSymbol(tile3img, p_x, p_y, symbol, s); break; case (MS_SYMBOL_ELLIPSE): status = renderer->renderEllipseSymbol(tile3img, p_x, p_y,symbol, s); break; case (MS_SYMBOL_VECTOR): status = renderer->renderVectorSymbol(tile3img, p_x, p_y, symbol, s); break; default: msSetError(MS_SYMERR, "BUG: Seamless mode is only for vector symbols", "getTile()"); return NULL; } if(UNLIKELY(status == MS_FAILURE)) { msFreeImage(tile3img); return NULL; } } } if(UNLIKELY(status == MS_FAILURE)) { msFreeImage(tile3img); return NULL; } status = MS_IMAGE_RENDERER(tile3img)->getRasterBufferHandle(tile3img,&tmpraster); if(UNLIKELY(status == MS_FAILURE)) { msFreeImage(tile3img); return NULL; } status = renderer->mergeRasterBuffer(tileimg, &tmpraster, 1.0,width,height,0,0,width,height ); msFreeImage(tile3img); } if(UNLIKELY(status == MS_FAILURE)) { msFreeImage(tileimg); return NULL; } tile = addTileCache(img,tileimg,symbol,s,width,height); } return tile->image; }
int msRenderSVGToPixmap(symbolObj *symbol, symbolStyleObj *style) { #ifdef USE_SVG_CAIRO unsigned int svg_width, svg_height; svg_cairo_status_t status; cairo_t *cr; svg_cairo_t *svgc; cairo_surface_t *surface; unsigned char *pb; rasterBufferObj *rb; //rendering_buffer *rc; int width, height, surface_w, surface_h,row; double scale; //already rendered at the right size and scale? return if (symbol->pixmap_buffer) { if (style->scale == symbol->pixmap_buffer->scale && style->rotation == symbol->pixmap_buffer->rotation) { return MS_SUCCESS; } else { if(symbol->renderer!=NULL) symbol->renderer->freeSymbol(symbol); msFreeRasterBuffer(symbol->pixmap_buffer); } } if (!symbol->svg_cairo_surface ) msPreloadSVGSymbol(symbol); if (!symbol->svg_cairo_surface) return MS_FAILURE; //set up raster svgc =symbol->svg_cairo_surface; svg_cairo_get_size (svgc, &svg_width, &svg_height); width = surface_w = svg_width; height = surface_h = svg_height; //scale such that the SVG is rendered at the desired size in pixels scale = style->scale; /*MS_MIN(style->scale / (double) svg_width, style->scale / (double) svg_height);*/ //increase pixmap size to accomodate scaling/rotation if (scale != 1.0 && style->scale != 1.0) { width = surface_w = (svg_width * scale + 0.5); height = surface_h = (svg_height * scale + 0.5); } if (style->rotation != 0) { surface_w = MS_NINT(width * 1.415); surface_h = MS_NINT(height * 1.415); } surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, surface_w, surface_h); cr = cairo_create(surface); if (style->rotation != 0) { cairo_translate (cr, surface_w/2, surface_h/2); cairo_rotate(cr, -style->rotation); cairo_translate (cr, -width/2, -height/2); } if (style->scale != 1.0) { cairo_scale(cr,scale,scale); } status = svg_cairo_render(svgc, cr); pb = cairo_image_surface_get_data(surface); //set up raster symbol->pixmap_buffer = (rasterBufferObj*)calloc(1,sizeof(rasterBufferObj)); MS_CHECK_ALLOC(symbol->pixmap_buffer, sizeof(rasterBufferObj), MS_FAILURE); initializeRasterBufferCairo(symbol->pixmap_buffer, surface_w, surface_h, 0); rb = symbol->pixmap_buffer; memcpy(rb->data.rgba.pixels, pb, surface_w * surface_h * 4 * sizeof(unsigned char)); /* unpremultiply the data */ for(row=0; row<rb->height; row++) { int col; unsigned char *a,*r,*g,*b; r=rb->data.rgba.r+row*rb->data.rgba.row_step; g=rb->data.rgba.g+row*rb->data.rgba.row_step; b=rb->data.rgba.b+row*rb->data.rgba.row_step; a=rb->data.rgba.a+row*rb->data.rgba.row_step; for(col=0; col<rb->width; col++) { if(*a && *a < 255) { double da = *a/255.0; *r/=da; *g/=da; *b/=da; } a+=rb->data.rgba.pixel_step; r+=rb->data.rgba.pixel_step; g+=rb->data.rgba.pixel_step; b+=rb->data.rgba.pixel_step; } } rb->scale = style->scale; rb->rotation = style->rotation; cairo_destroy(cr); cairo_surface_destroy(surface); return MS_SUCCESS; #else msSetError(MS_MISCERR, "SVG Symbols requested but MapServer is not built with libsvgcairo", "renderSVGSymbolCairo()"); return MS_FAILURE; #endif }
/* ** Returns the size, in pixels, of a marker symbol defined by a specific style and scalefactor. Used for annotation ** layer collision avoidance. A marker is made up of a number of styles so the calling code must either do the looping ** itself or call this function for the bottom style which should be the largest. */ int msGetMarkerSize(symbolSetObj *symbolset, styleObj *style, double *width, double *height, double scalefactor) { rectObj rect; int size; symbolObj *symbol; *width = *height = 0; /* set a starting value */ if(style->symbol > symbolset->numsymbols || style->symbol < 0) return(MS_FAILURE); /* no such symbol, 0 is OK */ if(style->symbol == 0) { /* single point */ *width = 1; *height = 1; return(MS_SUCCESS); } symbol = symbolset->symbol[style->symbol]; if (symbol->type == MS_SYMBOL_PIXMAP && !symbol->pixmap_buffer) { if (MS_SUCCESS != msPreloadImageSymbol(MS_MAP_RENDERER(symbolset->map), symbol)) return MS_FAILURE; } if(symbol->type == MS_SYMBOL_SVG && !symbol->renderer_cache) { #ifdef USE_SVG_CAIRO if(MS_SUCCESS != msPreloadSVGSymbol(symbol)) return MS_FAILURE; #else msSetError(MS_SYMERR, "SVG symbol support is not enabled.", "msGetMarkerSize()"); return MS_FAILURE; #endif } if(style->size == -1) { size = ( msSymbolGetDefaultSize(symbol) * scalefactor ); } else size = (style->size*scalefactor); size = MS_MAX(size, style->minsize); size = MS_MIN(size, style->maxsize); switch(symbol->type) { case(MS_SYMBOL_TRUETYPE): if(msGetTruetypeTextBBox(MS_MAP_RENDERER(symbolset->map),symbol->font,symbolset->fontset,size,symbol->character,&rect,NULL,0) != MS_SUCCESS) return(MS_FAILURE); *width = MS_MAX(*width, rect.maxx - rect.minx); *height = MS_MAX(*height, rect.maxy - rect.miny); break; case(MS_SYMBOL_PIXMAP): if(size == 1) { *width = MS_MAX(*width, symbol->pixmap_buffer->width); *height = MS_MAX(*height, symbol->pixmap_buffer->height); } else { *width = MS_MAX(*width, (((double)size/(double)symbol->pixmap_buffer->height) * symbol->pixmap_buffer->width)); *height = MS_MAX(*height, size); } break; default: /* vector and ellipses, scalable */ if(style->size > 0) { *width = MS_MAX(*width, ((size/symbol->sizey) * symbol->sizex)); *height = MS_MAX(*height, size); } else { /* use symbol defaults */ *width = MS_MAX(*width, symbol->sizex); *height = MS_MAX(*height, symbol->sizey); } break; } return(MS_SUCCESS); }