int renderPixmapSymbolCairo(imageObj *img, double x, double y,symbolObj *symbol, symbolStyleObj *style) { cairo_renderer *r = CAIRO_RENDERER(img); cairo_surface_t *im; rasterBufferObj *b = symbol->pixmap_buffer; assert(b); if(!symbol->renderer_cache) { symbol->renderer_cache = (void*)createSurfaceFromBuffer(b); } assert(symbol->renderer_cache); im=(cairo_surface_t*)symbol->renderer_cache; cairo_save(r->cr); if(style->rotation != 0 || style->scale != 1) { cairo_translate (r->cr, x,y); cairo_rotate (r->cr, -style->rotation); cairo_scale (r->cr, style->scale,style->scale); cairo_translate (r->cr, -0.5*b->width, -0.5*b->height); } else { cairo_translate (r->cr, MS_NINT(x-0.5*b->width),MS_NINT(y-0.5*b->height)); } cairo_set_source_surface (r->cr, im, 0, 0); cairo_paint (r->cr); cairo_restore(r->cr); return MS_SUCCESS; }
int agg2RenderLine(imageObj *img, shapeObj *p, strokeStyleObj *style) { AGG2Renderer *r = AGG_RENDERER(img); line_adaptor lines = line_adaptor(p); #ifdef AGG_ALIASED_ENABLED r->m_rasterizer_primitives.reset(); r->m_renderer_primitives.line_color(aggColor(style->color)); r->m_rasterizer_primitives.add_path(lines); return MS_SUCCESS; #endif r->m_rasterizer_aa.reset(); r->m_rasterizer_aa.filling_rule(mapserver::fill_non_zero); r->m_renderer_scanline.color(aggColor(style->color)); if (style->patternlength <= 0) { mapserver::conv_stroke<line_adaptor> stroke(lines); stroke.width(style->width); if(style->width>1) { applyCJC(stroke, style->linecap, style->linejoin); } else { stroke.inner_join(mapserver::inner_bevel); stroke.line_join(mapserver::bevel_join); } r->m_rasterizer_aa.add_path(stroke); } else { mapserver::conv_dash<line_adaptor> dash(lines); mapserver::conv_stroke<mapserver::conv_dash<line_adaptor> > stroke_dash(dash); int patt_length = 0; for (int i = 0; i < style->patternlength; i += 2) { if (i < style->patternlength - 1) { dash.add_dash(MS_MAX(1,MS_NINT(style->pattern[i])), MS_MAX(1,MS_NINT(style->pattern[i + 1]))); if(style->patternoffset) { patt_length += MS_MAX(1,MS_NINT(style->pattern[i])) + MS_MAX(1,MS_NINT(style->pattern[i + 1])); } } } if(style->patternoffset > 0) { dash.dash_start(patt_length - style->patternoffset); } stroke_dash.width(style->width); if(style->width>1) { applyCJC(stroke_dash, style->linecap, style->linejoin); } else { stroke_dash.inner_join(mapserver::inner_bevel); stroke_dash.line_join(mapserver::bevel_join); } r->m_rasterizer_aa.add_path(stroke_dash); } mapserver::render_scanlines(r->m_rasterizer_aa, r->sl_line, r->m_renderer_scanline); return MS_SUCCESS; }
int renderTileCairo(imageObj *img, imageObj *tile, double x, double y) { cairo_renderer *r = CAIRO_RENDERER(img); cairo_surface_t *im = CAIRO_RENDERER(tile)->surface; int w = cairo_image_surface_get_width (im); int h = cairo_image_surface_get_height (im); cairo_save(r->cr); cairo_translate(r->cr, MS_NINT(x-0.5 * w), MS_NINT(y -0.5 * h)); cairo_set_source_surface(r->cr, im, 0, 0); cairo_pattern_set_filter (cairo_get_source (r->cr), CAIRO_FILTER_NEAREST); cairo_paint(r->cr); cairo_restore(r->cr); return MS_SUCCESS; }
int renderGlyphsGD(imageObj *img, double x, double y, labelStyleObj *style, char *text) { #ifdef USE_GD_FREETYPE gdImagePtr ip; char *error=NULL; int bbox[8]; int c = 0,oc = 0; x = MS_NINT(x); y = MS_NINT(y); if(!(ip = MS_IMAGE_GET_GDIMAGEPTR(img))) return MS_FAILURE; if(!text || !strlen(text)) return(MS_SUCCESS); /* not errors, just don't want to do anything */ SETPEN(ip, style->color); SETPEN(ip, style->outlinecolor); if(style->antialias) { if(style->color) c = style->color->pen; if(style->outlinewidth > 0) oc = style->outlinecolor->pen; } else { if(style->color) c = -style->color->pen; if(style->outlinewidth > 0) oc = -style->outlinecolor->pen; } if(style->outlinewidth > 0) { /* handle the outline color */ error = gdImageStringFT(ip, bbox, oc, style->fonts[0], style->size, style->rotation, x, y-1, text); if(error) { msSetError(MS_TTFERR, "%s", "msDrawTextGD()", error); return(MS_FAILURE); } gdImageStringFT(ip, bbox, oc, style->fonts[0], style->size, style->rotation, x, y+1, text); gdImageStringFT(ip, bbox, oc, style->fonts[0], style->size, style->rotation, x+1, y, text); gdImageStringFT(ip, bbox, oc, style->fonts[0], style->size, style->rotation, x-1, y, text); gdImageStringFT(ip, bbox, oc, style->fonts[0], style->size, style->rotation, x-1, y-1, text); gdImageStringFT(ip, bbox, oc, style->fonts[0], style->size, style->rotation, x-1, y+1, text); gdImageStringFT(ip, bbox, oc, style->fonts[0], style->size, style->rotation, x+1, y-1, text); gdImageStringFT(ip, bbox, oc, style->fonts[0], style->size, style->rotation, x+1, y+1, text); } if(style->color) gdImageStringFT(ip, bbox, c, style->fonts[0], style->size, style->rotation, x, y, text); return MS_SUCCESS; #else msSetError(MS_TTFERR, "Freetype support not enabled in this GD build", "renderGlyphsGD()"); return MS_FAILURE; #endif }
/* assumes an angle of 0 regardless of what's in the label object */ int msGetLabelSize(mapObj *map, labelObj *label, char *string, double size, rectObj *rect, double **advances) { rendererVTableObj *renderer = NULL; if (map) renderer =MS_MAP_RENDERER(map); if(!renderer) { msSetError(MS_MISCERR, "cannot compute label size without valid map and renderer", "msGetLabelSize()"); return MS_FAILURE; } if(label->type == MS_TRUETYPE) { if(!label->font) { msSetError(MS_MISCERR, "label has no true type font", "msGetLabelSize()"); return MS_FAILURE; } return msGetTruetypeTextBBox(renderer,label->font,&(map->fontset),size,string,rect,advances,1); } else if(label->type == MS_BITMAP) { if(renderer->supports_bitmap_fonts) return msGetRasterTextBBox(renderer,MS_NINT(label->size),string,rect); else { msSetError(MS_MISCERR, "renderer does not support bitmap fonts", "msGetLabelSize()"); return MS_FAILURE; } } else { msSetError(MS_MISCERR, "unknown label type", "msGetLabelSize()"); return MS_FAILURE; } }
int agg2RenderPixmapSymbol(imageObj *img, double x, double y, symbolObj *symbol, symbolStyleObj * style) { AGG2Renderer *r = AGG_RENDERER(img); rasterBufferObj *pixmap = symbol->pixmap_buffer; assert(pixmap->type == MS_BUFFER_BYTE_RGBA); rendering_buffer b(pixmap->data.rgba.pixels,pixmap->width,pixmap->height,pixmap->data.rgba.row_step); pixel_format pf(b); r->m_rasterizer_aa.reset(); r->m_rasterizer_aa.filling_rule(mapserver::fill_non_zero); if ( (style->rotation != 0 && style->rotation != MS_PI*2.)|| style->scale != 1) { mapserver::trans_affine image_mtx; image_mtx *= mapserver::trans_affine_translation(-(pf.width()/2.),-(pf.height()/2.)); /*agg angles are antitrigonometric*/ image_mtx *= mapserver::trans_affine_rotation(-style->rotation); image_mtx *= mapserver::trans_affine_scaling(style->scale); image_mtx *= mapserver::trans_affine_translation(x,y); image_mtx.invert(); typedef mapserver::span_interpolator_linear<> interpolator_type; interpolator_type interpolator(image_mtx); mapserver::span_allocator<color_type> sa; // "hardcoded" bilinear filter //------------------------------------------ typedef mapserver::span_image_filter_rgba_bilinear_clip<pixel_format, interpolator_type> span_gen_type; span_gen_type sg(pf, mapserver::rgba(0,0,0,0), interpolator); mapserver::path_storage pixmap_bbox; int ims_2 = MS_NINT(MS_MAX(pixmap->width,pixmap->height)*style->scale*1.415)/2+1; pixmap_bbox.move_to(x-ims_2,y-ims_2); pixmap_bbox.line_to(x+ims_2,y-ims_2); pixmap_bbox.line_to(x+ims_2,y+ims_2); pixmap_bbox.line_to(x-ims_2,y+ims_2); r->m_rasterizer_aa.add_path(pixmap_bbox); mapserver::render_scanlines_aa(r->m_rasterizer_aa, r->sl_poly, r->m_renderer_base, sa, sg); } else { //just copy the image at the correct location (we place the pixmap on //the nearest integer pixel to avoid blurring) r->m_renderer_base.blend_from(pf,0,MS_NINT(x-pixmap->width/2.),MS_NINT(y-pixmap->height/2.)); } return MS_SUCCESS; }
int renderGlyphs2Cairo(imageObj *img, textPathObj *tp, colorObj *c, colorObj *oc, int ow) { cairo_renderer *r = CAIRO_RENDERER(img); cairoCacheData *cache = MS_IMAGE_RENDERER_CACHE(img); cairoFaceCache *cairo_face = NULL; FT_Face prevface = NULL; int g; cairo_set_font_size(r->cr,MS_NINT(tp->glyph_size * 96.0/72.0)); for(g=0;g<tp->numglyphs;g++) { glyphObj *gl = &tp->glyphs[g]; cairo_glyph_t glyph; /* load the glyph's face into cairo, if not already present */ if(gl->face->face != prevface) { cairo_face = getCairoFontFace(cache,gl->face->face); cairo_set_font_face(r->cr, cairo_face->face); cairo_set_font_options(r->cr,cairo_face->options); prevface = gl->face->face; cairo_set_font_size(r->cr,MS_NINT(tp->glyph_size * 96.0/72.0)); } cairo_save(r->cr); cairo_translate(r->cr,gl->pnt.x,gl->pnt.y); if(gl->rot != 0.0) cairo_rotate(r->cr, -gl->rot); glyph.x = glyph.y = 0; glyph.index = gl->glyph->key.codepoint; cairo_glyph_path(r->cr,&glyph,1); cairo_restore(r->cr); } if (oc) { cairo_save(r->cr); msCairoSetSourceColor(r->cr, oc); cairo_set_line_width(r->cr, ow + 1); cairo_stroke_preserve(r->cr); cairo_restore(r->cr); } if(c) { msCairoSetSourceColor(r->cr, c); cairo_fill(r->cr); } cairo_new_path(r->cr); return MS_SUCCESS; }
int agg2RenderBitmapGlyphs(imageObj *img, double x, double y, labelStyleObj *style, char *text) { typedef mapserver::glyph_raster_bin<color_type> glyph_gen; int size = MS_NINT(style->size); if(size<0 || size>4) { msSetError(MS_RENDERERERR,"invalid bitmap font size", "agg2RenderBitmapGlyphs()"); return MS_FAILURE; } AGG2Renderer *r = AGG_RENDERER(img); glyph_gen glyph(0); mapserver::renderer_raster_htext_solid<renderer_base, glyph_gen> rt(r->m_renderer_base, glyph); glyph.font(rasterfonts[size]); int numlines=0; char **lines; /*masking out the out-of-range character codes*/ int len; int cc_start = rasterfonts[size][2]; int cc_end = cc_start + rasterfonts[size][3]; if(msCountChars(text,'\n')) { if((lines = msStringSplit((const char*)text, '\n', &(numlines))) == NULL) return(-1); } else { lines = &text; numlines = 1; } y -= glyph.base_line(); for(int n=0; n<numlines; n++) { len = strlen(lines[n]); for (int i = 0; i < len; i++) if (lines[n][i] < cc_start || lines[n][i] > cc_end) lines[n][i] = '.'; if(style->outlinewidth > 0) { rt.color(aggColor(style->outlinecolor)); for(int i=-1; i<=1; i++) { for(int j=-1; j<=1; j++) { if(i||j) { rt.render_text(x+i, y+j, lines[n], true); } } } } assert(style->color); rt.color(aggColor(style->color)); rt.render_text(x, y, lines[n], true); y += glyph.height(); } if(*lines != text) msFreeCharArray(lines, numlines); return MS_SUCCESS; return MS_SUCCESS; }
int renderBitmapGlyphsGD(imageObj *img, double x, double y, labelStyleObj *style, char *text) { int size = MS_NINT(style->size); gdFontPtr fontPtr; gdImagePtr ip; int numlines=0,t; char **lines; if(!(ip = MS_IMAGE_GET_GDIMAGEPTR(img))) return MS_FAILURE; if(size<0 || size>4 || (fontPtr = msGetBitmapFont(size))==NULL) { msSetError(MS_RENDERERERR,"invalid bitmap font size", "renderBitmapGlyphsGD()"); return MS_FAILURE; } SETPEN(ip, style->color); SETPEN(ip, style->outlinecolor); if(msCountChars(text,'\n')) { if((lines = msStringSplit((const char*)text, '\n', &(numlines))) == NULL) return(-1); } else { lines = &text; numlines = 1; } y -= fontPtr->h; for(t=0; t<numlines; t++) { if(style->outlinewidth > 0) { gdImageString(ip, fontPtr, x, y-1, (unsigned char *) lines[t], style->outlinecolor->pen); gdImageString(ip, fontPtr, x, y+1, (unsigned char *) lines[t], style->outlinecolor->pen); gdImageString(ip, fontPtr, x+1, y, (unsigned char *) lines[t], style->outlinecolor->pen); gdImageString(ip, fontPtr, x-1, y, (unsigned char *) lines[t], style->outlinecolor->pen); gdImageString(ip, fontPtr, x+1, y-1, (unsigned char *) lines[t], style->outlinecolor->pen); gdImageString(ip, fontPtr, x+1, y+1, (unsigned char *) lines[t], style->outlinecolor->pen); gdImageString(ip, fontPtr, x-1, y-1, (unsigned char *) lines[t], style->outlinecolor->pen); gdImageString(ip, fontPtr, x-1, y+1, (unsigned char *) lines[t], style->outlinecolor->pen); } if(style->color->pen != -1) { gdImageString(ip, fontPtr, x, y, (unsigned char *) lines[t], style->color->pen); } y += fontPtr->h; /* shift down */ } if(lines != &text) msFreeCharArray(lines, numlines); return MS_SUCCESS; }
int msEmbedScalebar(mapObj *map, imageObj *img) { int l,index,s; pointObj point; imageObj *image = NULL; rendererVTableObj *renderer = MS_MAP_RENDERER(map); symbolObj *embededSymbol; if( ! renderer ) { msSetError(MS_MISCERR,"unsupported outputformat","msEmbedScalebar()"); return MS_FAILURE; } index = msGetSymbolIndex(&(map->symbolset), "scalebar", MS_FALSE); if(index != -1) msRemoveSymbol(&(map->symbolset), index); /* remove cached symbol in case the function is called multiple times with different zoom levels */ if((embededSymbol=msGrowSymbolSet(&map->symbolset)) == NULL) return MS_FAILURE; s = map->symbolset.numsymbols; map->symbolset.numsymbols++; image = msDrawScalebar(map); if(!image) { return MS_FAILURE; } embededSymbol->pixmap_buffer = calloc(1,sizeof(rasterBufferObj)); MS_CHECK_ALLOC(embededSymbol->pixmap_buffer, sizeof(rasterBufferObj), MS_FAILURE); if(MS_SUCCESS != renderer->getRasterBufferCopy(image,embededSymbol->pixmap_buffer)) { return MS_FAILURE; } embededSymbol->type = MS_SYMBOL_PIXMAP; /* intialize a few things */ embededSymbol->name = msStrdup("scalebar"); embededSymbol->sizex = embededSymbol->pixmap_buffer->width; embededSymbol->sizey = embededSymbol->pixmap_buffer->height; if(map->scalebar.transparent) { embededSymbol->transparent = MS_TRUE; embededSymbol->transparentcolor = 0; } switch(map->scalebar.position) { case(MS_LL): point.x = MS_NINT(embededSymbol->pixmap_buffer->width/2.0); point.y = map->height - MS_NINT(embededSymbol->pixmap_buffer->height/2.0); break; case(MS_LR): point.x = map->width - MS_NINT(embededSymbol->pixmap_buffer->width/2.0); point.y = map->height - MS_NINT(embededSymbol->pixmap_buffer->height/2.0); break; case(MS_LC): point.x = MS_NINT(map->width/2.0); point.y = map->height - MS_NINT(embededSymbol->pixmap_buffer->height/2.0); break; case(MS_UR): point.x = map->width - MS_NINT(embededSymbol->pixmap_buffer->width/2.0); point.y = MS_NINT(embededSymbol->pixmap_buffer->height/2.0); break; case(MS_UL): point.x = MS_NINT(embededSymbol->pixmap_buffer->width/2.0); point.y = MS_NINT(embededSymbol->pixmap_buffer->height/2.0); break; case(MS_UC): point.x = MS_NINT(map->width/2.0); point.y = MS_NINT(embededSymbol->pixmap_buffer->height/2.0); break; } l = msGetLayerIndex(map, "__embed__scalebar"); if(l == -1) { if (msGrowMapLayers(map) == NULL) return(-1); l = map->numlayers; map->numlayers++; if(initLayer((GET_LAYER(map, l)), map) == -1) return(-1); GET_LAYER(map, l)->name = msStrdup("__embed__scalebar"); GET_LAYER(map, l)->type = MS_LAYER_POINT; if (msGrowLayerClasses( GET_LAYER(map, l) ) == NULL) return(-1); if(initClass(GET_LAYER(map, l)->class[0]) == -1) return(-1); GET_LAYER(map, l)->numclasses = 1; /* so we make sure to free it */ /* update the layer order list with the layer's index. */ map->layerorder[l] = l; } GET_LAYER(map, l)->status = MS_ON; if(map->scalebar.postlabelcache) { /* add it directly to the image */ if(msMaybeAllocateClassStyle(GET_LAYER(map, l)->class[0], 0)==MS_FAILURE) return MS_FAILURE; GET_LAYER(map, l)->class[0]->styles[0]->symbol = s; msDrawMarkerSymbol(&map->symbolset, img, &point, GET_LAYER(map, l)->class[0]->styles[0], 1.0); } else { if(!GET_LAYER(map, l)->class[0]->labels) {
static double roundInterval(double d) { if(d<.001) return(MS_NINT(d*10000)/10000.0); if(d<.01) return(MS_NINT(d*1000)/1000.0); if(d<.1) return(MS_NINT(d*100)/100.0); if(d<1) return(MS_NINT(d*10)/10.0); if(d<100) return(MS_NINT(d)); if(d<1000) return(MS_NINT(d/10) * 10); if(d<10000) return(MS_NINT(d/100) * 100); if(d<100000) return(MS_NINT(d/1000) * 1000); if(d<1000000) return(MS_NINT(d/10000) * 10000); if(d<10000000) return(MS_NINT(d/100000) * 100000); if(d<100000000) return(MS_NINT(d/1000000) * 1000000); return(-1); }
/* * generic function for drawing a legend icon. (added for bug #2348) * renderer specific drawing functions shouldn't be called directly, but through * this function */ int msDrawLegendIcon(mapObj *map, layerObj *lp, classObj *theclass, int width, int height, imageObj *image, int dstX, int dstY, int scale_independant, class_hittest *hittest) { int i, type, hasmarkersymbol, ret=MS_SUCCESS; double offset; double polygon_contraction = 0.5; /* used to account for the width of a polygon's outline */ shapeObj box, zigzag; lineObj box_line,zigzag_line; pointObj box_point[5], zigzag_point[4]; pointObj marker; char szPath[MS_MAXPATHLEN]; styleObj outline_style; imageObj *image_draw = image; int originalopacity = lp->opacity; rendererVTableObj *renderer; outputFormatObj *transFormat = NULL, *altFormat=NULL; const char *alternativeFormatString = NULL; if(!MS_RENDERER_PLUGIN(image->format)) { msSetError(MS_MISCERR,"unsupported image format","msDrawLegendIcon()"); return MS_FAILURE; } alternativeFormatString = msLayerGetProcessingKey(lp, "RENDERER"); if (MS_RENDERER_PLUGIN(image_draw->format) && alternativeFormatString!=NULL && (altFormat= msSelectOutputFormat(map, alternativeFormatString))) { msInitializeRendererVTable(altFormat); image_draw = msImageCreate(image->width, image->height, altFormat, image->imagepath, image->imageurl, map->resolution, map->defresolution, &map->imagecolor); renderer = MS_IMAGE_RENDERER(image_draw); } else { renderer = MS_IMAGE_RENDERER(image_draw); if (lp->opacity > 0 && lp->opacity < 100) { if (!renderer->supports_transparent_layers) { image_draw = msImageCreate(image->width, image->height, image->format, image->imagepath, image->imageurl, map->resolution, map->defresolution, NULL); if (!image_draw) { msSetError(MS_MISCERR, "Unable to initialize temporary transparent image.", "msDrawLegendIcon()"); return (MS_FAILURE); } /* set opacity to full, as the renderer should be rendering a fully opaque image */ lp->opacity=100; } } } if(renderer->supports_clipping && MS_VALID_COLOR(map->legend.outlinecolor)) { /* keep GD specific code here for now as it supports clipping */ rectObj clip; clip.maxx = dstX + width - 1; clip.maxy = dstY + height -1; clip.minx = dstX; clip.miny = dstY; renderer->setClip(image_draw,clip); } /* if the class has a keyimage, treat it as a point layer * (the keyimage will be treated there) */ if(theclass->keyimage != NULL) { type = MS_LAYER_POINT; } else { /* some polygon layers may be better drawn using zigzag if there is no fill */ type = lp->type; if(type == MS_LAYER_POLYGON) { type = MS_LAYER_LINE; for(i=0; i<theclass->numstyles; i++) { if(MS_VALID_COLOR(theclass->styles[i]->color)) { /* there is a fill */ type = MS_LAYER_POLYGON; } if(MS_VALID_COLOR(theclass->styles[i]->outlinecolor)) { /* there is an outline */ polygon_contraction = MS_MAX(polygon_contraction, theclass->styles[i]->width / 2.0); } } } } /* initialize the box used for polygons and for outlines */ box.line = &box_line; box.numlines = 1; box.line[0].point = box_point; box.line[0].numpoints = 5; box.line[0].point[0].x = dstX + polygon_contraction; box.line[0].point[0].y = dstY + polygon_contraction; box.line[0].point[1].x = dstX + width - polygon_contraction; box.line[0].point[1].y = dstY + polygon_contraction; box.line[0].point[2].x = dstX + width - polygon_contraction; box.line[0].point[2].y = dstY + height - polygon_contraction; box.line[0].point[3].x = dstX + polygon_contraction; box.line[0].point[3].y = dstY + height - polygon_contraction; box.line[0].point[4].x = box.line[0].point[0].x; box.line[0].point[4].y = box.line[0].point[0].y; /* ** now draw the appropriate color/symbol/size combination */ switch(type) { case MS_LAYER_POINT: marker.x = dstX + MS_NINT(width / 2.0); marker.y = dstY + MS_NINT(height / 2.0); if(theclass->keyimage != NULL) { int symbolNum; styleObj imgStyle; symbolObj *symbol=NULL; for(symbolNum=0; symbolNum<theclass->numstyles; symbolNum++) symbolNum = msAddImageSymbol(&(map->symbolset), msBuildPath(szPath, map->mappath, theclass->keyimage)); if(symbolNum == -1) { msSetError(MS_IMGERR, "Failed to open legend key image", "msCreateLegendIcon()"); return(MS_FAILURE); } symbol = map->symbolset.symbol[symbolNum]; initStyle(&imgStyle); /*set size so that symbol will be scaled properly #3296*/ if (width/symbol->sizex < height/symbol->sizey) imgStyle.size = symbol->sizey*(width/symbol->sizex); else imgStyle.size = symbol->sizey*(height/symbol->sizey); if (imgStyle.size > imgStyle.maxsize) imgStyle.maxsize = imgStyle.size; imgStyle.symbol = symbolNum; ret = msDrawMarkerSymbol(map ,image_draw,&marker,&imgStyle,lp->scalefactor * image_draw->resolutionfactor); if(UNLIKELY(ret == MS_FAILURE)) goto legend_icon_cleanup; /* TO DO: we may want to handle this differently depending on the relative size of the keyimage */ } else { for(i=0; i<theclass->numstyles; i++) { if(!scale_independant && map->scaledenom > 0) { styleObj *lp = theclass->styles[i]; if((lp->maxscaledenom > 0) && (map->scaledenom > lp->maxscaledenom)) continue; if((lp->minscaledenom > 0) && (map->scaledenom <= lp->minscaledenom)) continue; } if(hittest && hittest->stylehits[i].status == 0) continue; ret = msDrawMarkerSymbol(map, image_draw, &marker, theclass->styles[i], lp->scalefactor * image->resolutionfactor); if(UNLIKELY(ret == MS_FAILURE)) goto legend_icon_cleanup; } } break; case MS_LAYER_LINE: offset = 1; /* To set the offset, we only check the size/width parameter of the first style */ if (theclass->numstyles > 0) { if (theclass->styles[0]->symbol > 0 && theclass->styles[0]->symbol < map->symbolset.numsymbols && map->symbolset.symbol[theclass->styles[0]->symbol]->type != MS_SYMBOL_SIMPLE) offset = theclass->styles[0]->size/2; else offset = theclass->styles[0]->width/2; } zigzag.line = &zigzag_line; zigzag.numlines = 1; zigzag.line[0].point = zigzag_point; zigzag.line[0].numpoints = 4; zigzag.line[0].point[0].x = dstX + offset; zigzag.line[0].point[0].y = dstY + height - offset; zigzag.line[0].point[1].x = dstX + MS_NINT(width / 3.0) - 1; zigzag.line[0].point[1].y = dstY + offset; zigzag.line[0].point[2].x = dstX + MS_NINT(2.0 * width / 3.0) - 1; zigzag.line[0].point[2].y = dstY + height - offset; zigzag.line[0].point[3].x = dstX + width - offset; zigzag.line[0].point[3].y = dstY + offset; for(i=0; i<theclass->numstyles; i++) { if(!scale_independant && map->scaledenom > 0) { styleObj *lp = theclass->styles[i]; if((lp->maxscaledenom > 0) && (map->scaledenom > lp->maxscaledenom)) continue; if((lp->minscaledenom > 0) && (map->scaledenom <= lp->minscaledenom)) continue; } if(hittest && hittest->stylehits[i].status == 0) continue; if (theclass->styles[i]->_geomtransform.type == MS_GEOMTRANSFORM_NONE || theclass->styles[i]->_geomtransform.type == MS_GEOMTRANSFORM_LABELPOINT || theclass->styles[i]->_geomtransform.type == MS_GEOMTRANSFORM_LABELPOLY) { ret = msDrawLineSymbol(map, image_draw, &zigzag, theclass->styles[i], lp->scalefactor * image_draw->resolutionfactor); if(UNLIKELY(ret == MS_FAILURE)) goto legend_icon_cleanup; } else { ret = msDrawTransformedShape(map, image_draw, &zigzag, theclass->styles[i], lp->scalefactor * image_draw->resolutionfactor); if(UNLIKELY(ret == MS_FAILURE)) goto legend_icon_cleanup; } } break; case MS_LAYER_CIRCLE: case MS_LAYER_RASTER: case MS_LAYER_CHART: case MS_LAYER_POLYGON: for(i=0; i<theclass->numstyles; i++) { if(!scale_independant && map->scaledenom > 0) { styleObj *lp = theclass->styles[i]; if((lp->maxscaledenom > 0) && (map->scaledenom > lp->maxscaledenom)) continue; if((lp->minscaledenom > 0) && (map->scaledenom <= lp->minscaledenom)) continue; } if(hittest && hittest->stylehits[i].status == 0) continue; if (theclass->styles[i]->_geomtransform.type == MS_GEOMTRANSFORM_NONE || theclass->styles[i]->_geomtransform.type == MS_GEOMTRANSFORM_LABELPOINT || theclass->styles[i]->_geomtransform.type == MS_GEOMTRANSFORM_LABELPOLY) { ret = msDrawShadeSymbol(map, image_draw, &box, theclass->styles[i], lp->scalefactor * image_draw->resolutionfactor); if(UNLIKELY(ret == MS_FAILURE)) goto legend_icon_cleanup; } else { ret = msDrawTransformedShape(map, image_draw, &box, theclass->styles[i], lp->scalefactor); if(UNLIKELY(ret == MS_FAILURE)) goto legend_icon_cleanup; } } break; default: return MS_FAILURE; break; } /* end symbol drawing */ /* handle label styles */ for(i=0; i<theclass->numlabels; i++) { labelObj *l = theclass->labels[i]; if(!scale_independant && map->scaledenom > 0) { if(msScaleInBounds(map->scaledenom, l->minscaledenom, l->maxscaledenom)) { int j; for(j=0; j<l->numstyles; j++) { styleObj *s = l->styles[j]; marker.x = dstX + MS_NINT(width / 2.0); marker.y = dstY + MS_NINT(height / 2.0); if(s->_geomtransform.type == MS_GEOMTRANSFORM_LABELPOINT) { ret = msDrawMarkerSymbol(map, image_draw, &marker, s, lp->scalefactor); if(UNLIKELY(ret == MS_FAILURE)) goto legend_icon_cleanup; } } } } } /* handle "pure" text layers, i.e. layers with no symbology */ hasmarkersymbol = 0; if(theclass->numstyles == 0) { for(i=0; i<theclass->numlabels; i++) { labelObj *l = theclass->labels[i]; if(!scale_independant && map->scaledenom > 0) { if(msScaleInBounds(map->scaledenom, l->minscaledenom, l->maxscaledenom)) { int j; for(j=0; j<l->numstyles; j++) { styleObj *s = l->styles[j]; if(s->_geomtransform.type == MS_GEOMTRANSFORM_LABELPOINT) { hasmarkersymbol = 1; } } } } } } else { hasmarkersymbol = 1; } if(!hasmarkersymbol && theclass->numlabels>0) { textSymbolObj ts; pointObj textstartpt; marker.x = dstX + MS_NINT(width / 2.0); marker.y = dstY + MS_NINT(height / 2.0); initTextSymbol(&ts); msPopulateTextSymbolForLabelAndString(&ts,theclass->labels[0],msStrdup("Az"),lp->scalefactor*image_draw->resolutionfactor,image_draw->resolutionfactor, duplicate_always); ts.label->size = height - 1; ret = msComputeTextPath(map,&ts); if(UNLIKELY(ret == MS_FAILURE)) goto legend_icon_cleanup; textstartpt = get_metrics(&marker,MS_CC,ts.textpath,0,0,0,0,NULL); ret = msDrawTextSymbol(map,image_draw, textstartpt, &ts); freeTextSymbol(&ts); if(UNLIKELY(ret == MS_FAILURE)) goto legend_icon_cleanup; } /* handle an outline if necessary */ if(MS_VALID_COLOR(map->legend.outlinecolor)) { initStyle(&outline_style); outline_style.color = map->legend.outlinecolor; ret = msDrawLineSymbol(map, image_draw, &box, &outline_style, image_draw->resolutionfactor); if(UNLIKELY(ret == MS_FAILURE)) goto legend_icon_cleanup; /* reset clipping rectangle */ if(renderer->supports_clipping) renderer->resetClip(image_draw); } if (altFormat) { rendererVTableObj *renderer = MS_IMAGE_RENDERER(image); rendererVTableObj *altrenderer = MS_IMAGE_RENDERER(image_draw); rasterBufferObj rb; memset(&rb,0,sizeof(rasterBufferObj)); ret = altrenderer->getRasterBufferHandle(image_draw,&rb); if(UNLIKELY(ret == MS_FAILURE)) goto legend_icon_cleanup; ret = renderer->mergeRasterBuffer(image,&rb,lp->opacity*0.01,0,0,0,0,rb.width,rb.height); if(UNLIKELY(ret == MS_FAILURE)) goto legend_icon_cleanup; /* * hack to work around bug #3834: if we have use an alternate renderer, the symbolset may contain * symbols that reference it. We want to remove those references before the altFormat is destroyed * to avoid a segfault and/or a leak, and so the the main renderer doesn't pick the cache up thinking * it's for him. */ for(i=0; i<map->symbolset.numsymbols; i++) { if (map->symbolset.symbol[i]!=NULL) { symbolObj *s = map->symbolset.symbol[i]; if(s->renderer == altrenderer) { altrenderer->freeSymbol(s); s->renderer = NULL; } } } } else if(image != image_draw) { rendererVTableObj *renderer = MS_IMAGE_RENDERER(image_draw); rasterBufferObj rb; memset(&rb,0,sizeof(rasterBufferObj)); lp->opacity = originalopacity; ret = renderer->getRasterBufferHandle(image_draw,&rb); if(UNLIKELY(ret == MS_FAILURE)) goto legend_icon_cleanup; ret = renderer->mergeRasterBuffer(image,&rb,lp->opacity*0.01,0,0,0,0,rb.width,rb.height); if(UNLIKELY(ret == MS_FAILURE)) goto legend_icon_cleanup; /* deref and possibly free temporary transparent output format. */ msApplyOutputFormat( &transFormat, NULL, MS_NOOVERRIDE, MS_NOOVERRIDE, MS_NOOVERRIDE ); } legend_icon_cleanup: if(image != image_draw) { msFreeImage(image_draw); } return ret; }
/* TODO : the will be msDrawScalebarGD */ imageObj *msDrawScalebar(mapObj *map) { int status; char label[32]; double i, msx; int j; int isx, sx, sy, ox, oy, state, dsx; pointObj p; rectObj r; imageObj *image = NULL; double fontWidth, fontHeight; outputFormatObj *format = NULL; strokeStyleObj strokeStyle; shapeObj shape; lineObj line; pointObj points[5]; rendererVTableObj *renderer; strokeStyle.patternlength=0; if(map->units == -1) { msSetError(MS_MISCERR, "Map units not set.", "msDrawScalebar()"); return(NULL); } renderer = MS_MAP_RENDERER(map); if(!renderer || !MS_MAP_RENDERER(map)->supports_pixel_buffer) { msSetError(MS_MISCERR, "Outputformat not supported for scalebar", "msDrawScalebar()"); return(NULL); } /* * A string containing the ten decimal digits is rendered to compute an average cell size * for each number, which is used later to place labels on the scalebar. */ if(msGetLabelSize(map,&map->scalebar.label,"0123456789",map->scalebar.label.size,&r,NULL) != MS_SUCCESS) { return NULL; } fontWidth = (r.maxx-r.minx)/10.0; fontHeight = r.maxy -r.miny; map->cellsize = msAdjustExtent(&(map->extent), map->width, map->height); status = msCalculateScale(map->extent, map->units, map->width, map->height, map->resolution, &map->scaledenom); if(status != MS_SUCCESS) { return(NULL); } dsx = map->scalebar.width - 2*HMARGIN; do { msx = (map->cellsize * dsx)/(msInchesPerUnit(map->scalebar.units,0)/msInchesPerUnit(map->units,0)); i = roundInterval(msx/map->scalebar.intervals); snprintf(label, sizeof(label), "%g", map->scalebar.intervals*i); /* last label */ isx = MS_NINT((i/(msInchesPerUnit(map->units,0)/msInchesPerUnit(map->scalebar.units,0)))/map->cellsize); sx = (map->scalebar.intervals*isx) + MS_NINT((1.5 + strlen(label)/2.0 + strlen(unitText[map->scalebar.units]))*fontWidth); if(sx <= (map->scalebar.width - 2*HMARGIN)) break; /* it will fit */ dsx -= X_STEP_SIZE; /* change the desired size in hopes that it will fit in user supplied width */ } while(1); sy = (2*VMARGIN) + MS_NINT(VSPACING*fontHeight) + fontHeight + map->scalebar.height - VSLOP; /*Ensure we have an image format representing the options for the scalebar.*/ msApplyOutputFormat( &format, map->outputformat, map->scalebar.transparent, map->scalebar.interlace, MS_NOOVERRIDE ); if(map->scalebar.transparent == MS_OFF) { if(!MS_VALID_COLOR(map->scalebar.imagecolor)) MS_INIT_COLOR(map->scalebar.imagecolor,255,255,255,255); } image = msImageCreate(map->scalebar.width, sy, format, map->web.imagepath, map->web.imageurl, map->resolution, map->defresolution, &map->scalebar.imagecolor); /* drop this reference to output format */ msApplyOutputFormat( &format, NULL, MS_NOOVERRIDE, MS_NOOVERRIDE, MS_NOOVERRIDE ); /* did we succeed in creating the image? */ if(!image) { msSetError(MS_MISCERR, "Unable to initialize image.", "msDrawScalebar()"); return NULL; } switch(map->scalebar.align) { case(MS_ALIGN_LEFT): ox = HMARGIN; break; case(MS_ALIGN_RIGHT): ox = MS_NINT((map->scalebar.width - sx) + fontWidth); break; default: ox = MS_NINT((map->scalebar.width - sx)/2.0 + fontWidth/2.0); /* center the computed scalebar */ } oy = VMARGIN; switch(map->scalebar.style) { case(0): { line.numpoints = 5; line.point = points; shape.line = &line; shape.numlines = 1; if(MS_VALID_COLOR(map->scalebar.color)) { INIT_STROKE_STYLE(strokeStyle); strokeStyle.color = &map->scalebar.outlinecolor; strokeStyle.color->alpha = 255; strokeStyle.width = 1; } map->scalebar.backgroundcolor.alpha = 255; map->scalebar.color.alpha = 255; state = 1; /* 1 means filled */ for(j=0; j<map->scalebar.intervals; j++) { points[0].x = points[4].x = points[3].x = ox + j*isx + 0.5; points[0].y = points[4].y = points[1].y = oy + 0.5; points[1].x = points[2].x = ox + (j+1)*isx + 0.5; points[2].y = points[3].y = oy + map->scalebar.height + 0.5; if(state == 1 && MS_VALID_COLOR(map->scalebar.color)) renderer->renderPolygon(image,&shape,&map->scalebar.color); else if(MS_VALID_COLOR(map->scalebar.backgroundcolor)) renderer->renderPolygon(image,&shape,&map->scalebar.backgroundcolor); if(strokeStyle.color) renderer->renderLine(image,&shape,&strokeStyle); sprintf(label, "%g", j*i); map->scalebar.label.position = MS_CC; p.x = ox + j*isx; /* + MS_NINT(fontPtr->w/2); */ p.y = oy + map->scalebar.height + MS_NINT(VSPACING*fontHeight); msDrawLabel(map,image,p,label,&map->scalebar.label,1.0); state = -state; } sprintf(label, "%g", j*i); ox = ox + j*isx - MS_NINT((strlen(label)*fontWidth)/2.0); sprintf(label, "%g %s", j*i, unitText[map->scalebar.units]); map->scalebar.label.position = MS_CR; p.x = ox; /* + MS_NINT(fontPtr->w/2); */ p.y = oy + map->scalebar.height + MS_NINT(VSPACING*fontHeight); msDrawLabel(map,image,p,label,&map->scalebar.label,1.0); break; } case(1): { line.numpoints = 2; line.point = points; shape.line = &line; shape.numlines = 1; if(MS_VALID_COLOR(map->scalebar.color)) { strokeStyle.width = 1; strokeStyle.color = &map->scalebar.color; } points[0].y = points[1].y = oy; points[0].x = ox; points[1].x = ox + isx*map->scalebar.intervals; renderer->renderLine(image,&shape,&strokeStyle); points[0].y = oy; points[1].y = oy + map->scalebar.height; p.y = oy + map->scalebar.height + MS_NINT(VSPACING*fontHeight); for(j=0; j<=map->scalebar.intervals; j++) { points[0].x = points[1].x = ox + j*isx; renderer->renderLine(image,&shape,&strokeStyle); sprintf(label, "%g", j*i); if(j!=map->scalebar.intervals) { map->scalebar.label.position = MS_CC; p.x = ox + j*isx; /* + MS_NINT(fontPtr->w/2); */ } else { sprintf(label, "%g %s", j*i, unitText[map->scalebar.units]); map->scalebar.label.position = MS_CR; p.x = ox + j*isx - MS_NINT((strlen(label)*fontWidth)/2.0); } msDrawLabel(map,image,p,label,&map->scalebar.label,1.0); } break; } default: msSetError(MS_MISCERR, "Unsupported scalebar style.", "msDrawScalebar()"); return(NULL); } return(image); }
int msAddLabelGroup(mapObj *map, int layerindex, int classindex, shapeObj *shape, pointObj *point, double featuresize) { int i, priority, numactivelabels=0; labelCacheSlotObj *cacheslot; labelCacheMemberObj *cachePtr=NULL; layerObj *layerPtr=NULL; classObj *classPtr=NULL; layerPtr = (GET_LAYER(map, layerindex)); /* set up a few pointers for clarity */ classPtr = GET_LAYER(map, layerindex)->class[classindex]; if(classPtr->numlabels == 0) return MS_SUCCESS; /* not an error just nothing to do */ for(i=0; i<classPtr->numlabels; i++) { if(classPtr->labels[i]->status == MS_ON) { numactivelabels++; } } if(numactivelabels == 0) return MS_SUCCESS; /* if the number of labels is 1 then call msAddLabel() accordingly */ if(numactivelabels == 1) { for(i=0; i<classPtr->numlabels; i++) { if(classPtr->labels[i]->status == MS_ON) return msAddLabel(map, classPtr->labels[i], layerindex, classindex, shape, point, NULL, featuresize); } } if (layerPtr->type == MS_LAYER_ANNOTATION && (classPtr->numlabels > 1 || classPtr->leader.maxdistance)) { msSetError(MS_MISCERR, "Multiple Labels and/or LEADERs are not supported with annotation layers", "msAddLabelGroup()"); return MS_FAILURE; } /* check that the label intersects the layer mask */ if(layerPtr->mask) { int maskLayerIdx = msGetLayerIndex(map,layerPtr->mask); layerObj *maskLayer = GET_LAYER(map,maskLayerIdx); unsigned char *alphapixptr; if(maskLayer->maskimage && MS_IMAGE_RENDERER(maskLayer->maskimage)->supports_pixel_buffer) { rasterBufferObj rb; int x,y; memset(&rb,0,sizeof(rasterBufferObj)); MS_IMAGE_RENDERER(maskLayer->maskimage)->getRasterBufferHandle(maskLayer->maskimage,&rb); x = MS_NINT(point->x); y = MS_NINT(point->y); /* Using label repeatdistance, we might have a point with x/y below 0. See #4764 */ if (x >= 0 && x < rb.width && y >= 0 && y < rb.height) { #ifdef USE_GD if(rb.type == MS_BUFFER_BYTE_RGBA) { alphapixptr = rb.data.rgba.a+rb.data.rgba.row_step*y + rb.data.rgba.pixel_step*x; if(!*alphapixptr) { /* label point does not intersect mask */ return MS_SUCCESS; } } else { if(!gdImageGetPixel(rb.data.gd_img,x,y)) return MS_SUCCESS; } #else assert(rb.type == MS_BUFFER_BYTE_RGBA); alphapixptr = rb.data.rgba.a+rb.data.rgba.row_step*y + rb.data.rgba.pixel_step*x; if(!*alphapixptr) { /* label point does not intersect mask */ return MS_SUCCESS; } #endif } } else { msSetError(MS_MISCERR, "Layer (%s) references references a mask layer, but the selected renderer does not support them", "msAddLabelGroup()", layerPtr->name); return (MS_FAILURE); } } /* Validate label priority value and get ref on label cache for it */ priority = classPtr->labels[0]->priority; /* take priority from the first label */ if (priority < 1) priority = 1; else if (priority > MS_MAX_LABEL_PRIORITY) priority = MS_MAX_LABEL_PRIORITY; cacheslot = &(map->labelcache.slots[priority-1]); if(cacheslot->numlabels == cacheslot->cachesize) { /* just add it to the end */ cacheslot->labels = (labelCacheMemberObj *) realloc(cacheslot->labels, sizeof(labelCacheMemberObj)*(cacheslot->cachesize+MS_LABELCACHEINCREMENT)); MS_CHECK_ALLOC(cacheslot->labels, sizeof(labelCacheMemberObj)*(cacheslot->cachesize+MS_LABELCACHEINCREMENT), MS_FAILURE); cacheslot->cachesize += MS_LABELCACHEINCREMENT; } cachePtr = &(cacheslot->labels[cacheslot->numlabels]); cachePtr->layerindex = layerindex; /* so we can get back to this *raw* data if necessary */ cachePtr->classindex = classindex; if(shape) { cachePtr->shapetype = shape->type; } else { cachePtr->shapetype = MS_SHAPE_POINT; } cachePtr->point = *point; /* the actual label point */ cachePtr->labelpath = NULL; cachePtr->leaderline = NULL; cachePtr->leaderbbox = NULL; // cachePtr->text = msStrdup(string); /* the actual text */ /* TODO: perhaps we can get rid of this next section and just store a marker size? Why do we cache the styles for a point layer? */ /* copy the styles (only if there is an accompanying marker) * We cannot simply keep refs because the rendering code might alters some members of the style objects */ cachePtr->styles = NULL; cachePtr->numstyles = 0; if(layerPtr->type == MS_LAYER_ANNOTATION && classPtr->numstyles > 0) { cachePtr->numstyles = classPtr->numstyles; cachePtr->styles = (styleObj *) msSmallMalloc(sizeof(styleObj)*classPtr->numstyles); if (classPtr->numstyles > 0) { for(i=0; i<classPtr->numstyles; i++) { initStyle(&(cachePtr->styles[i])); msCopyStyle(&(cachePtr->styles[i]), classPtr->styles[i]); } } } /* ** copy the labels (we are guaranteed to have more than one): ** we cannot simply keep refs because the rendering code alters some members of the style objects */ cachePtr->numlabels = 0; cachePtr->labels = (labelObj *) msSmallMalloc(sizeof(labelObj)*numactivelabels); for(i=0; i<classPtr->numlabels; i++) { if(classPtr->labels[i]->status == MS_OFF) continue; initLabel(&(cachePtr->labels[cachePtr->numlabels])); msCopyLabel(&(cachePtr->labels[cachePtr->numlabels]), classPtr->labels[i]); cachePtr->numlabels++; } assert(cachePtr->numlabels == numactivelabels); cachePtr->markerid = -1; cachePtr->featuresize = featuresize; //cachePtr->poly = (shapeObj *) msSmallMalloc(sizeof(shapeObj)); //msInitShape(cachePtr->poly); cachePtr->poly = NULL; cachePtr->status = MS_FALSE; if(layerPtr->type == MS_LAYER_POINT && classPtr->numstyles > 0) { /* cache the marker placement, it's already on the map */ /* TO DO: at the moment only checks the bottom style, perhaps should check all of them */ /* #2347: after RFC-24 classPtr->styles could be NULL so we check it */ rectObj rect; double w, h; if(msGetMarkerSize(&map->symbolset, classPtr->styles[0], &w, &h, layerPtr->scalefactor) != MS_SUCCESS) return(MS_FAILURE); if(cacheslot->nummarkers == cacheslot->markercachesize) { /* just add it to the end */ cacheslot->markers = (markerCacheMemberObj *) realloc(cacheslot->markers, sizeof(markerCacheMemberObj)*(cacheslot->cachesize+MS_LABELCACHEINCREMENT)); MS_CHECK_ALLOC(cacheslot->markers, sizeof(markerCacheMemberObj)*(cacheslot->cachesize+MS_LABELCACHEINCREMENT), MS_FAILURE); cacheslot->markercachesize+=MS_LABELCACHEINCREMENT; } i = cacheslot->nummarkers; cacheslot->markers[i].poly = (shapeObj *) msSmallMalloc(sizeof(shapeObj)); msInitShape(cacheslot->markers[i].poly); rect.minx = (point->x - .5 * w); rect.miny = (point->y - .5 * h); rect.maxx = rect.minx + (w-1); rect.maxy = rect.miny + (h-1); msRectToPolygon(rect, cacheslot->markers[i].poly); cacheslot->markers[i].id = cacheslot->numlabels; cachePtr->markerid = i; cacheslot->nummarkers++; } cacheslot->numlabels++; /* Maintain main labelCacheObj.numlabels only for backwards compatibility */ map->labelcache.numlabels++; return(MS_SUCCESS); }
/* ------------------------------------------------------------------------- */ void msDrawMarkerSymbolIM(mapObj *map, imageObj* img, pointObj *p, styleObj *style, double scalefactor) { symbolObj *symbol; int ox, oy; double size; DEBUG_IF printf("msDrawMarkerSymbolIM\n<BR>"); /* skip this, we don't do text */ if(!p) return; if(style->symbol > map->symbolset.numsymbols || style->symbol < 0) return; /* no such symbol, 0 is OK */ symbol = map->symbolset.symbol[style->symbol]; ox = style->offsetx*scalefactor; oy = style->offsety*scalefactor; if(style->size == -1) { size = msSymbolGetDefaultSize( symbol ); size = MS_NINT(size*scalefactor); } else size = MS_NINT(style->size*scalefactor); size = MS_MAX(size, style->minsize*img->resolutionfactor); size = MS_MIN(size, style->maxsize*img->resolutionfactor); if(size < 1) return; /* size too small */ /* DEBUG_IF printf(".%d.%d.%d.", symbol->type, style->symbol, fc); */ if(style->symbol == 0) { /* simply draw a single pixel of the specified color */ if (dxf) { if (dxf==2) im_iprintf (&imgStr, "POINT\n%.0f %.0f\n%d\n", p->x + ox, p->y + oy, matchdxfcolor(style->color)); else im_iprintf (&imgStr, " 0\nPOINT\n 10\n%f\n 20\n%f\n 30\n0.0\n" " 62\n%6d\n 8\n%s\n", p->x + ox, p->y + oy, matchdxfcolor(style->color), lname); } else { im_iprintf (&imgStr, "<area "); if (strcmp(symbolHrefFmt,"%.s")!=0) { im_iprintf (&imgStr, "href=\""); im_iprintf (&imgStr, symbolHrefFmt, lname); im_iprintf (&imgStr, "\" "); } if (strcmp(symbolMOverFmt,"%.s")!=0) { im_iprintf (&imgStr, "onMouseOver=\""); im_iprintf (&imgStr, symbolMOverFmt, lname); im_iprintf (&imgStr, "\" "); } if (strcmp(symbolMOutFmt,"%.s")!=0) { im_iprintf (&imgStr, "onMouseOut=\""); im_iprintf (&imgStr, symbolMOutFmt, lname); im_iprintf (&imgStr, "\" "); } im_iprintf (&imgStr, "shape=\"circle\" coords=\"%.0f,%.0f, 3\" />\n", p->x + ox, p->y + oy); } /* point2 = &( p->line[j].point[i] ); */ /* if(point1->y == point2->y) {} */ return; } DEBUG_IF printf("A"); switch(symbol->type) { case(MS_SYMBOL_TRUETYPE): DEBUG_IF printf("T"); break; case(MS_SYMBOL_PIXMAP): DEBUG_IF printf("P"); break; case(MS_SYMBOL_VECTOR): DEBUG_IF printf("V"); { double d, offset_x, offset_y; d = size/symbol->sizey; offset_x = MS_NINT(p->x - d*.5*symbol->sizex + ox); offset_y = MS_NINT(p->y - d*.5*symbol->sizey + oy); /* For now I only render filled vector symbols in imagemap, and no */ /* dxf support available yet. */ if(symbol->filled && !dxf /* && fc >= 0 */ ) { /* char *title=(p->numvalues) ? p->values[0] : ""; */ char *title = ""; int j; im_iprintf (&imgStr, "<area "); if (strcmp(symbolHrefFmt,"%.s")!=0) { im_iprintf (&imgStr, "href=\""); im_iprintf (&imgStr, symbolHrefFmt, lname); im_iprintf (&imgStr, "\" "); } if (strcmp(symbolMOverFmt,"%.s")!=0) { im_iprintf (&imgStr, "onMouseOver=\""); im_iprintf (&imgStr, symbolMOverFmt, lname); im_iprintf (&imgStr, "\" "); } if (strcmp(symbolMOutFmt,"%.s")!=0) { im_iprintf (&imgStr, "onMouseOut=\""); im_iprintf (&imgStr, symbolMOutFmt, lname); im_iprintf (&imgStr, "\" "); } im_iprintf (&imgStr, "title=\"%s\" shape=\"poly\" coords=\"", title); for(j=0; j < symbol->numpoints; j++) { im_iprintf (&imgStr, "%s %d,%d", j == 0 ? "": ",", MS_NINT(d*symbol->points[j].x + offset_x), MS_NINT(d*symbol->points[j].y + offset_y) ); } im_iprintf (&imgStr, "\" />\n"); } /* end of imagemap, filled case. */ } break; default: DEBUG_IF printf("DEF"); break; } /* end switch statement */ return; }
char *msAlignText(mapObj *map, labelObj *label, char *text) { double spacewidth=0.0; /*size of a single space, in fractional pixels*/ int numlines; char **textlines,*newtext,*newtextptr; int *textlinelengths,*numspacesforpadding; int numspacestoadd,maxlinelength,i; rectObj label_rect; if(!msCountChars(text,'\n')) return text; /*only one line*/ /*split text into individual lines * TODO: check if splitting on \n is utf8 safe*/ textlines = msStringSplit(text,'\n',&numlines); /* * label->space_size_10 contains a cache for the horizontal size of a single * 'space' character, at size 10 for the current label * FIXME: in case of attribute binding for the FONT of the label, this cache will * be wrong for labels where the attributed font is different than the first * computed font. This shouldn't happen too often, and hopefully the size of a * space character shouldn't vary too much between different fonts*/ if(label->space_size_10 == 0.0) { /*if the cache hasn't been initialized yet, or with pixmap fonts*/ /* compute the size of 16 adjacent spaces. we can't do this for just one space, * as the labelSize computing functions return integer bounding boxes. we assume * that the integer rounding for such a number of spaces will be negligeable * compared to the actual size of thoses spaces */ if(msGetLabelSize(map,label,". .",10.0,&label_rect,NULL) != MS_SUCCESS) { /*error computing label size, we can't continue*/ /*free the previously allocated split text*/ while(numlines--) free(textlines[numlines]); free(textlines); return text; } /* this is the size of a single space character. for truetype fonts, * it's the size of a 10pt space. For pixmap fonts, it's the size * for the current label */ spacewidth = (label_rect.maxx-label_rect.minx)/16.0; if(label->type == MS_TRUETYPE) { label->space_size_10=spacewidth; /*cache the computed size*/ /*size of a space for current label size*/ spacewidth = spacewidth * (double)label->size/10.0; } } else { spacewidth = label->space_size_10 * (double)label->size/10.0; } spacewidth = MS_MAX(1,spacewidth); /*length in pixels of each line*/ textlinelengths = (int*)msSmallMalloc(numlines*sizeof(int)); /*number of spaces that need to be added to each line*/ numspacesforpadding = (int*)msSmallMalloc(numlines*sizeof(int)); /*total number of spaces that need to be added*/ numspacestoadd=0; /*length in pixels of the longest line*/ maxlinelength=0; for(i=0; i<numlines; i++) { if(MS_SUCCESS != msGetLabelSize(map,label,textlines[i],label->size, &label_rect,NULL)) { msFreeCharArray(textlines,numlines); msFree(textlinelengths); msFree(numspacesforpadding); return text; } textlinelengths[i] = label_rect.maxx-label_rect.minx; if(maxlinelength<textlinelengths[i]) maxlinelength=textlinelengths[i]; } for(i=0; i<numlines; i++) { /* number of spaces to add so the current line is * as long as the longest line */ double nfracspaces = (maxlinelength - textlinelengths[i])/spacewidth; if(label->align == MS_ALIGN_CENTER) { numspacesforpadding[i]=MS_NINT(nfracspaces/2.0); } else { if(label->align == MS_ALIGN_RIGHT) { numspacesforpadding[i]=MS_NINT(nfracspaces); } } numspacestoadd+=numspacesforpadding[i]; } /*allocate new text with room for the additional spaces needed*/ newtext = (char*)msSmallMalloc(strlen(text)+1+numspacestoadd); newtextptr=newtext; for(i=0; i<numlines; i++) { int j; /*padd beginning of line with needed spaces*/ for(j=0; j<numspacesforpadding[i]; j++) { *(newtextptr++)=' '; } /*copy original line*/ strcpy(newtextptr,textlines[i]); /*place pointer at the char right after the current line*/ newtextptr+=strlen(textlines[i])+1; if(i!=numlines-1) { /*put the \n back in (was taken away by msStringSplit)*/ *(newtextptr-1)='\n'; } } /*free the original text*/ free(text); for(i=0; i<numlines; i++) { free(textlines[i]); } free(textlines); free(textlinelengths); free(numspacesforpadding); /*return the aligned text. note that the terminating \0 was added by the last * call to strcpy */ return newtext; }
int renderLineGD(imageObj *img, shapeObj *p, strokeStyleObj *stroke) { gdImagePtr ip; int c; gdImagePtr brush=NULL; if(!img || !p || !stroke) return MS_FAILURE; if(!(ip = MS_IMAGE_GET_GDIMAGEPTR(img))) return MS_FAILURE; SETPEN(ip, stroke->color); c = stroke->color->pen; if(stroke->patternlength > 0) { int *style; int i, j, k=0; int sc; for(i=0; i<stroke->patternlength; i++) k += MS_NINT(stroke->pattern[i]); style = (int *) malloc (k * sizeof(int)); MS_CHECK_ALLOC(style, k * sizeof(int), MS_FAILURE); sc = c; /* start with the color */ k=0; for(i=0; i<stroke->patternlength; i++) { for(j=0; j<MS_NINT(stroke->pattern[i]); j++, k++) { style[k] = sc; } sc = ((sc==c)?gdTransparent:c); } gdImageSetStyle(ip, style, k); free(style); c = gdStyled; } if(stroke->width > 1) { int brush_fc; brush = gdImageCreate(ceil(stroke->width), ceil(stroke->width)); gdImageColorAllocate(brush, gdImageRed(ip,0), gdImageGreen(ip, 0), gdImageBlue(ip, 0)); gdImageColorTransparent(brush,0); brush_fc = gdImageColorAllocate(brush, gdImageRed(ip,stroke->color->pen), gdImageGreen(ip,stroke->color->pen), gdImageBlue(ip,stroke->color->pen)); gdImageFilledEllipse(brush,MS_NINT(brush->sx/2),MS_NINT(brush->sy/2), MS_NINT(stroke->width),MS_NINT(stroke->width), brush_fc); gdImageSetBrush(ip, brush); if(stroke->patternlength > 0) { c = gdStyledBrushed; } else { c = gdBrushed; } } /* finally draw something */ imagePolyline(ip, p, c); /* clean up */ if(stroke->width>1) { gdImageDestroy(brush); } return MS_SUCCESS; }
int renderVectorSymbolGD(imageObj *img, double x, double y, symbolObj *symbol, symbolStyleObj *style) { int bRotated = MS_FALSE; int j,k; gdImagePtr ip; gdPoint mPoints[MS_MAXVECTORPOINTS]; gdPoint oldpnt,newpnt; int fc,oc; if(!(ip = MS_IMAGE_GET_GDIMAGEPTR(img))) return MS_FAILURE; SETPEN(ip, style->color); SETPEN(ip, style->outlinecolor); fc = style->color ? style->color->pen : -1; oc = style->outlinecolor ? style->outlinecolor->pen : -1; if(oc==-1 && fc ==-1) { return MS_SUCCESS; } if (style->rotation != 0.0) { bRotated = MS_TRUE; symbol = rotateVectorSymbolPoints(symbol, style->rotation); if(!symbol) { return MS_FAILURE; } } /* We avoid MS_NINT in this context because the potentially variable handling of 0.5 rounding is often a problem for symbols which are often an odd size (ie. 7pixels) and so if "p" is integral the value is always on a 0.5 boundary - bug 1716 */ x -= style->scale*.5*symbol->sizex; y -= style->scale*.5*symbol->sizey; if(symbol->filled) { /* if filled */ k = 0; /* point counter */ for(j=0; j < symbol->numpoints; j++) { if((symbol->points[j].x == -99) && (symbol->points[j].y == -99)) { /* new polygon (PENUP) */ if(k>2) { if(fc >= 0) gdImageFilledPolygon(ip, mPoints, k, fc); if(oc >= 0) gdImagePolygon(ip, mPoints, k, oc); } k = 0; /* reset point counter */ } else { mPoints[k].x = MS_NINT(style->scale*symbol->points[j].x + x); mPoints[k].y = MS_NINT(style->scale*symbol->points[j].y + y); k++; } } if(fc >= 0) gdImageFilledPolygon(ip, mPoints, k, fc); if(oc >= 0) gdImagePolygon(ip, mPoints, k, oc); } else { /* NOT filled */ if(oc >= 0) fc = oc; /* try the outline color (reference maps sometimes do this when combining a box and a custom vector marker */ oldpnt.x = MS_NINT(style->scale*symbol->points[0].x + x); /* convert first point in marker */ oldpnt.y = MS_NINT(style->scale*symbol->points[0].y + y); gdImageSetThickness(ip, style->outlinewidth); for(j=1; j < symbol->numpoints; j++) { /* step through the marker */ if((symbol->points[j].x != -99) || (symbol->points[j].y != -99)) { if((symbol->points[j-1].x == -99) && (symbol->points[j-1].y == -99)) { /* Last point was PENUP, now a new beginning */ oldpnt.x = MS_NINT(style->scale*symbol->points[j].x + x); oldpnt.y = MS_NINT(style->scale*symbol->points[j].y + y); } else { newpnt.x = MS_NINT(style->scale*symbol->points[j].x + x); newpnt.y = MS_NINT(style->scale*symbol->points[j].y + y); gdImageLine(ip, oldpnt.x, oldpnt.y, newpnt.x, newpnt.y, fc); oldpnt = newpnt; } } } /* end for loop */ gdImageSetThickness(ip, 1); /* restore thinkness */ } /* end if-then-else */ if(bRotated) { msFreeSymbol(symbol); /* clean up */ msFree(symbol); } return MS_SUCCESS; }
xmlNodePtr KmlRenderer::createGroundOverlayNode(xmlNodePtr parentNode, char *imageHref, layerObj *layer) { /* <?xml version="1.0" encoding="UTF-8"?> <kml xmlns="http://www.opengis.net/kml/2.2"> <GroundOverlay> <name>GroundOverlay.kml</name> <color>7fffffff</color> <drawOrder>1</drawOrder> <Icon> <href>http://www.google.com/intl/en/images/logo.gif</href> <refreshMode>onInterval</refreshMode> <refreshInterval>86400</refreshInterval> <viewBoundScale>0.75</viewBoundScale> </Icon> <LatLonBox> <north>37.83234</north> <south>37.832122</south> <east>-122.373033</east> <west>-122.373724</west> <rotation>45</rotation> </LatLonBox> </GroundOverlay> </kml> */ char layerHexColor[32]; xmlNodePtr groundOverlayNode = xmlNewChild(parentNode, NULL, BAD_CAST "GroundOverlay", NULL); char *layerName = getLayerName(layer); xmlNewChild(groundOverlayNode, NULL, BAD_CAST "name", BAD_CAST layerName); if (layer->compositer && layer->compositer->opacity > 0 && layer->compositer->opacity < 100) { sprintf(layerHexColor, "%02xffffff", (unsigned int)MS_NINT(layer->compositer->opacity*2.55)); xmlNewChild(groundOverlayNode, NULL, BAD_CAST "color", BAD_CAST layerHexColor); } else xmlNewChild(groundOverlayNode, NULL, BAD_CAST "color", BAD_CAST "ffffffff"); char stmp[20]; sprintf(stmp, "%d",layer->index); xmlNewChild(groundOverlayNode, NULL, BAD_CAST "drawOrder", BAD_CAST stmp); if (imageHref) { xmlNodePtr iconNode = xmlNewChild(groundOverlayNode, NULL, BAD_CAST "Icon", NULL); xmlNewChild(iconNode, NULL, BAD_CAST "href", BAD_CAST imageHref); } char crdStr[64]; rectObj mapextent; if (map->gt.need_geotransform == MS_TRUE) mapextent = currentLayer->map->saved_extent; else mapextent = currentLayer->map->extent; xmlNodePtr latLonBoxNode = xmlNewChild(groundOverlayNode, NULL, BAD_CAST "LatLonBox", NULL); sprintf(crdStr, "%.8f", mapextent.maxy); xmlNewChild(latLonBoxNode, NULL, BAD_CAST "north", BAD_CAST crdStr); sprintf(crdStr, "%.8f", mapextent.miny); xmlNewChild(latLonBoxNode, NULL, BAD_CAST "south", BAD_CAST crdStr); sprintf(crdStr, "%.8f", mapextent.minx); xmlNewChild(latLonBoxNode, NULL, BAD_CAST "west", BAD_CAST crdStr); sprintf(crdStr, "%.8f", mapextent.maxx); xmlNewChild(latLonBoxNode, NULL, BAD_CAST "east", BAD_CAST crdStr); xmlNewChild(latLonBoxNode, NULL, BAD_CAST "rotation", BAD_CAST "0.0"); return groundOverlayNode; }
int msDrawLineSymbol(mapObj *map, imageObj *image, shapeObj *p, styleObj *style, double scalefactor) { int status = MS_SUCCESS; if (image) { if (MS_RENDERER_PLUGIN(image->format)) { rendererVTableObj *renderer = image->format->vtable; symbolObj *symbol; shapeObj *offsetLine = p; int i; double width; double finalscalefactor; if (p->numlines == 0) return MS_SUCCESS; if (style->symbol >= map->symbolset.numsymbols || style->symbol < 0) return MS_SUCCESS; /* no such symbol, 0 is OK */ symbol = map->symbolset.symbol[style->symbol]; /* store a reference to the renderer to be used for freeing */ symbol->renderer = renderer; width = style->width * scalefactor; width = MS_MIN(width,style->maxwidth*image->resolutionfactor); width = MS_MAX(width,style->minwidth*image->resolutionfactor); if(style->width != 0) { finalscalefactor = width / style->width; } else { finalscalefactor = 1.0; } if(style->offsety==MS_STYLE_SINGLE_SIDED_OFFSET) { offsetLine = msOffsetPolyline(p,style->offsetx * finalscalefactor ,MS_STYLE_SINGLE_SIDED_OFFSET); } else if(style->offsety==MS_STYLE_DOUBLE_SIDED_OFFSET) { offsetLine = msOffsetPolyline(p,style->offsetx * finalscalefactor ,MS_STYLE_DOUBLE_SIDED_OFFSET); } else if(style->offsetx!=0 || style->offsety!=0) { offsetLine = msOffsetPolyline(p, style->offsetx * finalscalefactor, style->offsety * finalscalefactor); } if(style->symbol == 0 || (symbol->type==MS_SYMBOL_SIMPLE)) { strokeStyleObj s; s.linecap = style->linecap; s.linejoin = style->linejoin; s.linejoinmaxsize = style->linejoinmaxsize; s.width = width; s.patternlength = style->patternlength; for(i=0; i<s.patternlength; i++) s.pattern[i] = style->pattern[i] * finalscalefactor; s.patternoffset = (style->initialgap<=0) ? 0 : (style->initialgap * finalscalefactor); if(MS_VALID_COLOR(style->color)) s.color = &style->color; else if(MS_VALID_COLOR(style->outlinecolor)) s.color = &style->outlinecolor; else { /* msSetError(MS_MISCERR,"no color defined for line styling","msDrawLineSymbol()"); * not really an error */ status = MS_SUCCESS; goto draw_line_cleanup; } status = renderer->renderLine(image,offsetLine,&s); } else { symbolStyleObj s; if(preloadSymbol(&map->symbolset, symbol, renderer) != MS_SUCCESS) { return MS_FAILURE; } INIT_SYMBOL_STYLE(s); computeSymbolStyle(&s,style,symbol,scalefactor,image->resolutionfactor); s.style = style; /* compute a markerStyle and use it on the line */ if(style->gap<0) { /* special function that treats any other symbol used as a marker, not a brush */ status = msImagePolylineMarkers(image,offsetLine,symbol,&s,-s.gap, style->initialgap * finalscalefactor, 1); } else if(style->gap>0) { status = msImagePolylineMarkers(image,offsetLine,symbol,&s,s.gap, style->initialgap * finalscalefactor,0); } else { if(renderer->renderLineTiled != NULL) { int pw,ph; imageObj* tile=NULL; if(s.scale != 1) { pw = MS_NINT(symbol->sizex * s.scale); ph = MS_NINT(symbol->sizey * s.scale); } else { pw = symbol->sizex; ph = symbol->sizey; } if(pw<1) pw=1; if(ph<1) ph=1; tile = getTile(image, symbol,&s,pw,ph,0); status = renderer->renderLineTiled(image, offsetLine, tile); } else { msSetError(MS_RENDERERERR, "renderer does not support brushed lines", "msDrawLineSymbol()"); status = MS_FAILURE; } } } draw_line_cleanup: if(offsetLine!=p) { msFreeShape(offsetLine); msFree(offsetLine); } } else if( MS_RENDERER_IMAGEMAP(image->format) ) msDrawLineSymbolIM(map, image, p, style, scalefactor); else { msSetError(MS_RENDERERERR, "unsupported renderer", "msDrawShadeSymbol()"); status = MS_FAILURE; } } else { status = MS_FAILURE; } return status; }
int main(int argc, char *argv[]) { FILE *stream; int ns,n,k; gdImagePtr img; shapeObj p; int i,j; int ncols,nrows; char buffer[256]; int gray, green, red, black, white; classObj class; symbolSetObj symbolSet; /* ---- check the number of arguments, return syntax if not correct ---- */ if( argc < 2 ) { fprintf(stdout, "Syntax: sym2img [symbolset] [outfile]\n" ); exit(0); } /* Initialize the polygon/polyline */ p.line = (lineObj *)malloc(sizeof(lineObj)); p.numlines = 1; p.line[0].point = (pointObj *)malloc(sizeof(pointObj)*4); p.line[0].numpoints = 4; /* Initialize the symbol and font sets */ symbolSet.filename = msStrdup(argv[1]); /* ** load the symbol file */ if(msLoadSymbolSet(&symbolSet) == -1) { msWriteError(stderr); exit(1); } ns = symbolSet.numsymbols; if(ns < NCOLS) { ncols = ns; nrows = 1; } else { ncols = NCOLS; nrows = (int)ceil((double)ns/NCOLS); } img = gdImageCreate(ncols*CELLSIZE, nrows*CELLSIZE); gray = gdImageColorAllocate(img, 222, 222, 222); white = gdImageColorAllocate(img, 255, 255, 255); green = gdImageColorAllocate(img, 40, 170, 40); black = gdImageColorAllocate(img, 0, 0, 0); red = gdImageColorAllocate(img, 255, 0, 0); class.color = red; class.backgroundcolor = white; class.outlinecolor = black; n=0; for(i=0; n<ns;i+=CELLSIZE) { k=0; for(j=0; n<ns;j+=CELLSIZE) { if (k == ncols) break; k++; gdImageFilledRectangle(img,j,i,j+CELLSIZE, i+CELLSIZE, gray); class.symbol = n; switch(symbolSet.type) { case(MS_MARKERSET): class.sizescaled = RATIO*CELLSIZE; p.line[0].point[0].x = MS_NINT(j + CELLSIZE/2); p.line[0].point[0].y = MS_NINT(i + CELLSIZE/2); p.line[0].numpoints = 1; msDrawMarkerSymbol(&(symbolSet), img, &(p.line[0].point[0]), &(class)); break; case(MS_LINESET): class.sizescaled = 1; p.line[0].point[0].x = j; p.line[0].point[0].y = i + (CELLSIZE-LBUF) - 1; p.line[0].point[1].x = j + MS_NINT((CELLSIZE-LBUF)/3.0) - 1; p.line[0].point[1].y = i; p.line[0].point[2].x = j + MS_NINT(2*(CELLSIZE-LBUF)/3.0) - 1; p.line[0].point[2].y = i + (CELLSIZE-LBUF) - 1; p.line[0].point[3].x = j + (CELLSIZE-LBUF) - 1; p.line[0].point[3].y = i; p.line[0].numpoints = 4; msDrawLineSymbol(&(symbolSet), img, &p, &(class)); break; case(MS_SHADESET): class.sizescaled = 5; p.line[0].point[0].x = j; p.line[0].point[0].y = i; p.line[0].point[1].x = j + CELLSIZE-1; p.line[0].point[1].y = i; p.line[0].point[2].x = j + CELLSIZE-1; p.line[0].point[2].y = i + CELLSIZE-1 ; p.line[0].point[3].x = j; p.line[0].point[3].y = i + CELLSIZE-1; p.line[0].numpoints = 4; msDrawShadeSymbol(&(symbolSet), img, &p, &(class)); break; default: break; } if(symbolSet.symbol[n]->name) snprintf(buffer, sizeof(buffer), "%d - %s", n, symbolSet.symbol[n]->name); else snprintf(buffer, sizeof(buffer), "%d", n); gdImageString(img, gdFontTiny, j+1, i+1, buffer, black); n++; } } if((stream = fopen(argv[2],"wb")) == NULL) { /* open the file */ fprintf(stderr, "Unable to open output file: %s\n", argv[2]); exit(1); } #ifndef USE_GD_1_6 gdImageGif(img, stream); #else gdImagePng(img, stream); #endif gdImageDestroy(img); free(symbolSet.filename); fclose(stream); return(MS_TRUE); }
int renderGlyphsCairo(imageObj *img,double x, double y, labelStyleObj *style, char *text) { cairo_renderer *r = CAIRO_RENDERER(img); cairoCacheData *cache = MS_IMAGE_RENDERER_CACHE(img); faceCacheObj *face = getFontFace(cache,style->font); char *utfptr=text; int i,has_kerning,unicode; unsigned long previdx=0; int numglyphs = msGetNumGlyphs(text); cairo_glyph_t glyph; cairo_text_extents_t extents; double px=0,py=0; if(face == NULL) { return MS_FAILURE; } cairo_set_font_face(r->cr,face->face); cairo_set_font_size(r->cr,style->size*96/72.0); cairo_save(r->cr); cairo_translate(r->cr,MS_NINT(x),MS_NINT(y)); if(style->rotation != 0.0) cairo_rotate(r->cr, -style->rotation); has_kerning = FT_HAS_KERNING((face->ftface)); for(i=0;i<numglyphs;i++) { utfptr+=msUTF8ToUniChar(utfptr, &unicode); glyph.x=px; glyph.y=py; if(unicode=='\n') { py += ceil(style->size*CAIROLINESPACE); px = 0; previdx=0; continue; } glyph.index = FT_Get_Char_Index(face->ftface, unicode); if( has_kerning && previdx ) { FT_Vector delta; FT_Get_Kerning( face->ftface, previdx, glyph.index, FT_KERNING_DEFAULT, &delta ); px += delta.x / 64.; } cairo_glyph_extents(r->cr,&glyph,1,&extents); cairo_glyph_path(r->cr,&glyph,1); px += extents.x_advance; previdx=glyph.index; } if (style->outlinewidth > 0) { cairo_save(r->cr); msCairoSetSourceColor(r->cr, style->outlinecolor); cairo_set_line_width(r->cr, style->outlinewidth + 1); cairo_stroke_preserve(r->cr); cairo_restore(r->cr); } if(style->color) { msCairoSetSourceColor(r->cr, style->color); cairo_fill(r->cr); } cairo_new_path(r->cr); cairo_restore(r->cr); return MS_SUCCESS; }
/* * generic function for drawing a legend icon. (added for bug #2348) * renderer specific drawing functions shouldn't be called directly, but through * this function */ int msDrawLegendIcon(mapObj *map, layerObj *lp, classObj *theclass, int width, int height, imageObj *image, int dstX, int dstY) { int i, type, hasmarkersymbol; double offset; shapeObj box, zigzag; pointObj marker; char szPath[MS_MAXPATHLEN]; styleObj outline_style; imageObj *image_draw = image; int originalopacity = lp->opacity; rendererVTableObj *renderer; outputFormatObj *transFormat = NULL, *altFormat=NULL; const char *alternativeFormatString = NULL; if(!MS_RENDERER_PLUGIN(image->format)) { msSetError(MS_MISCERR,"unsupported image format","msDrawLegendIcon()"); return MS_FAILURE; } alternativeFormatString = msLayerGetProcessingKey(lp, "RENDERER"); if (MS_RENDERER_PLUGIN(image_draw->format) && alternativeFormatString!=NULL && (altFormat= msSelectOutputFormat(map, alternativeFormatString))) { msInitializeRendererVTable(altFormat); image_draw = msImageCreate(image->width, image->height, altFormat, image->imagepath, image->imageurl, map->resolution, map->defresolution, &map->imagecolor); renderer = MS_IMAGE_RENDERER(image_draw); } else { renderer = MS_IMAGE_RENDERER(image_draw); if (lp->opacity > 0 && lp->opacity < 100) { if (!renderer->supports_transparent_layers) { image_draw = msImageCreate(image->width, image->height, image->format, image->imagepath, image->imageurl, map->resolution, map->defresolution, NULL); if (!image_draw) { msSetError(MS_MISCERR, "Unable to initialize temporary transparent image.", "msDrawLegendIcon()"); return (MS_FAILURE); } /* set opacity to full, as the renderer should be rendering a fully opaque image */ lp->opacity=100; } } } if(renderer->supports_clipping && MS_VALID_COLOR(map->legend.outlinecolor)) { /* keep GD specific code here for now as it supports clipping */ rectObj clip; clip.maxx = dstX + width - 1; clip.maxy = dstY + height -1; clip.minx = dstX; clip.miny = dstY; renderer->setClip(image_draw,clip); } /* initialize the box used for polygons and for outlines */ box.line = (lineObj *)msSmallMalloc(sizeof(lineObj)); box.numlines = 1; box.line[0].point = (pointObj *)msSmallMalloc(sizeof(pointObj)*5); box.line[0].numpoints = 5; box.line[0].point[0].x = dstX + 0.5; box.line[0].point[0].y = dstY + 0.5; box.line[0].point[1].x = dstX + width - 0.5; box.line[0].point[1].y = dstY + 0.5; box.line[0].point[2].x = dstX + width - 0.5; box.line[0].point[2].y = dstY + height - 0.5; box.line[0].point[3].x = dstX + 0.5; box.line[0].point[3].y = dstY + height - 0.5; box.line[0].point[4].x = box.line[0].point[0].x; box.line[0].point[4].y = box.line[0].point[0].y; box.line[0].numpoints = 5; /* if the class has a keyimage, treat it as a point layer * (the keyimage will be treated there) */ if(theclass->keyimage != NULL) { type = MS_LAYER_POINT; } else { /* some polygon layers may be better drawn using zigzag if there is no fill */ type = lp->type; if(type == MS_LAYER_POLYGON) { type = MS_LAYER_LINE; for(i=0; i<theclass->numstyles; i++) { if(MS_VALID_COLOR(theclass->styles[i]->color)) { /* there is a fill */ type = MS_LAYER_POLYGON; break; } } } } /* ** now draw the appropriate color/symbol/size combination */ switch(type) { case MS_LAYER_ANNOTATION: marker.x = dstX + MS_NINT(width / 2.0); marker.y = dstY + MS_NINT(height / 2.0); hasmarkersymbol = 0; for(i=0; i<theclass->numstyles; i++) { if (theclass->styles[i]->symbol < map->symbolset.numsymbols && theclass->styles[i]->symbol > 0) { hasmarkersymbol = 1; break; } } if (hasmarkersymbol) { for(i=0; i<theclass->numstyles; i++) msDrawMarkerSymbol(&map->symbolset, image_draw, &marker, theclass->styles[i], lp->scalefactor); } else if (theclass->labels && theclass->numlabels > 0) { labelObj *label = theclass->labels[0]; /* use the first label definition */ double lsize = label->size; double langle = label->angle; int lpos = label->position; int loffsetx = label->offsetx; int loffsety = label->offsety; label->offsetx = 0; label->offsety = 0; label->angle = 0; label->position = MS_CC; if (label->type == MS_TRUETYPE) label->size = height; msDrawLabel(map, image_draw, marker, (char*)"Az", label,1.0); label->size = lsize; label->position = lpos; label->angle = langle; label->offsetx = loffsetx; label->offsety = loffsety; } break; case MS_LAYER_POINT: marker.x = dstX + MS_NINT(width / 2.0); marker.y = dstY + MS_NINT(height / 2.0); if(theclass->keyimage != NULL) { int symbolNum; styleObj imgStyle; symbolObj *symbol=NULL; symbolNum = msAddImageSymbol(&(map->symbolset), msBuildPath(szPath, map->mappath, theclass->keyimage)); if(symbolNum == -1) { msSetError(MS_GDERR, "Failed to open legend key image", "msCreateLegendIcon()"); return(MS_FAILURE); } symbol = map->symbolset.symbol[symbolNum]; initStyle(&imgStyle); /*set size so that symbol will be scaled properly #3296*/ if (width/symbol->sizex < height/symbol->sizey) imgStyle.size = symbol->sizey*(width/symbol->sizex); else imgStyle.size = symbol->sizey*(height/symbol->sizey); if (imgStyle.size > imgStyle.maxsize) imgStyle.maxsize = imgStyle.size; imgStyle.symbol = symbolNum; msDrawMarkerSymbol(&map->symbolset,image_draw,&marker,&imgStyle,lp->scalefactor); /* TO DO: we may want to handle this differently depending on the relative size of the keyimage */ } else { for(i=0; i<theclass->numstyles; i++) msDrawMarkerSymbol(&map->symbolset, image_draw, &marker, theclass->styles[i], lp->scalefactor); } break; case MS_LAYER_LINE: offset = 1; /* To set the offset, we only check the size/width parameter of the first style */ if (theclass->numstyles > 0) { if (theclass->styles[0]->symbol > 0 && theclass->styles[0]->symbol < map->symbolset.numsymbols && map->symbolset.symbol[theclass->styles[0]->symbol]->type != MS_SYMBOL_SIMPLE) offset = theclass->styles[0]->size/2; else offset = theclass->styles[0]->width/2; } zigzag.line = (lineObj *)msSmallMalloc(sizeof(lineObj)); zigzag.numlines = 1; zigzag.line[0].point = (pointObj *)msSmallMalloc(sizeof(pointObj)*4); zigzag.line[0].numpoints = 4; zigzag.line[0].point[0].x = dstX + offset; zigzag.line[0].point[0].y = dstY + height - offset; zigzag.line[0].point[1].x = dstX + MS_NINT(width / 3.0) - 1; zigzag.line[0].point[1].y = dstY + offset; zigzag.line[0].point[2].x = dstX + MS_NINT(2.0 * width / 3.0) - 1; zigzag.line[0].point[2].y = dstY + height - offset; zigzag.line[0].point[3].x = dstX + width - offset; zigzag.line[0].point[3].y = dstY + offset; for(i=0; i<theclass->numstyles; i++) msDrawLineSymbol(&map->symbolset, image_draw, &zigzag, theclass->styles[i], lp->scalefactor); free(zigzag.line[0].point); free(zigzag.line); break; case MS_LAYER_CIRCLE: case MS_LAYER_RASTER: case MS_LAYER_CHART: case MS_LAYER_POLYGON: for(i=0; i<theclass->numstyles; i++) msDrawShadeSymbol(&map->symbolset, image_draw, &box, theclass->styles[i], lp->scalefactor); break; default: return MS_FAILURE; break; } /* end symbol drawing */ /* handle an outline if necessary */ if(MS_VALID_COLOR(map->legend.outlinecolor)) { initStyle(&outline_style); outline_style.color = map->legend.outlinecolor; msDrawLineSymbol(&map->symbolset, image_draw, &box, &outline_style, 1.0); /* reset clipping rectangle */ if(renderer->supports_clipping) renderer->resetClip(image_draw); } if (altFormat) { rendererVTableObj *renderer = MS_IMAGE_RENDERER(image); rendererVTableObj *altrenderer = MS_IMAGE_RENDERER(image_draw); rasterBufferObj rb; memset(&rb,0,sizeof(rasterBufferObj)); altrenderer->getRasterBufferHandle(image_draw,&rb); renderer->mergeRasterBuffer(image,&rb,lp->opacity*0.01,0,0,0,0,rb.width,rb.height); /* * hack to work around bug #3834: if we have use an alternate renderer, the symbolset may contain * symbols that reference it. We want to remove those references before the altFormat is destroyed * to avoid a segfault and/or a leak, and so the the main renderer doesn't pick the cache up thinking * it's for him. */ for(i=0; i<map->symbolset.numsymbols; i++) { if (map->symbolset.symbol[i]!=NULL) { symbolObj *s = map->symbolset.symbol[i]; if(s->renderer == altrenderer) { altrenderer->freeSymbol(s); s->renderer = NULL; } } } msFreeImage(image_draw); } else if(image != image_draw) { rendererVTableObj *renderer = MS_IMAGE_RENDERER(image_draw); rasterBufferObj rb; memset(&rb,0,sizeof(rasterBufferObj)); lp->opacity = originalopacity; renderer->getRasterBufferHandle(image_draw,&rb); renderer->mergeRasterBuffer(image,&rb,lp->opacity*0.01,0,0,0,0,rb.width,rb.height); msFreeImage(image_draw); /* deref and possibly free temporary transparent output format. */ msApplyOutputFormat( &transFormat, NULL, MS_NOOVERRIDE, MS_NOOVERRIDE, MS_NOOVERRIDE ); } free(box.line[0].point); free(box.line); return MS_SUCCESS; }
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 }
/* ** Polygon fill. Based on "Concave Polygon Scan Conversion" by Paul ** Heckbert from "Graphics Gems", Academic Press, 1990. ** */ static void imageFilledPolygon(gdImagePtr im, shapeObj *p, int c) { typedef struct { /* a polygon edge */ double x; /* x coordinate of edge's intersection with current scanline */ double dx; /* change in x with respect to y */ int i; /* point index */ int l; /* line number */ int s; /* scanline */ } pEdge; pointObj *point1, *point2; int k, l, i, j, xl, xr, ymin, ymax, y, n,nvert, nact, m; int wrong_order; pEdge *edge, *temp; pEdge **active; int *yhist, *edgeindex; if(p->numlines == 0) return; n=0; for(i=0; i<p->numlines; i++) { n += p->line[i].numpoints; } if(n == 0) return; edge = (pEdge *) msSmallCalloc(n,sizeof(pEdge)); /* All edges in the polygon */ edgeindex = (int *) msSmallCalloc(n,sizeof(int)); /* Index to edges sorted by scanline */ active = (pEdge **) msSmallCalloc(n,sizeof(pEdge*)); /* Pointers to active edges for current scanline */ nvert=0; ymin= (int) ceil(p->line[0].point[0].y-0.5); ymax= (int) floor(p->line[0].point[0].y-0.5); /* populate the edge table */ for(l=0; l<p->numlines; l++) { for(i=0; i < p->line[l].numpoints; i++) { j = i < p->line[l].numpoints -1 ? i+1 : 0; if (p->line[l].point[i].y < p->line[l].point[j].y ) { point1 = &(p->line[l].point[i]); point2 = &(p->line[l].point[j]); } else { point2 = &(p->line[l].point[i]); point1 = &(p->line[l].point[j]); } edge[nvert].dx = point2->y == point1->y ? 0 : (point2->x - point1->x) / (point2->y - point1->y); edge[nvert].s = MS_NINT( p->line[l].point[i].y ); /* ceil( p->line[l].point[i].y - 0.5 ); */ edge[nvert].x = point1->x; edge[nvert].i = nvert; edge[nvert].l = l; ymin = MS_MIN(ymin,edge[nvert].s); ymax = MS_MAX(ymax,edge[nvert].s); nvert++; } } /* Use histogram sort to create a bucket-sorted edgeindex by scanline */ yhist = (int*) msSmallCalloc(ymax - ymin + 2, sizeof(int)); for(i=0; i<nvert; i++) { yhist[ edge[i].s - ymin + 1 ]++; } for(i=0; i<=(ymax - ymin); i++) {/* Calculate starting point in edgeindex for each scanline */ yhist[i+1] += yhist[i]; } for(i=0; i<nvert; i++) { /* Bucket sort edges into edgeindex */ y = edge[i].s; edgeindex[yhist[y-ymin]] = i; yhist[y-ymin]++; } free(yhist); k=0; nact=0; for (y=ymin; y<=ymax; y++) { /* step through scanlines */ /* scanline y is at y+.5 in continuous coordinates */ /* check vertices between previous scanline and current one, if any */ for (; k<nvert && edge[edgeindex[k]].s <= y; k++) { i = edge[edgeindex[k]].i; /* vertex previous to i */ if(i==0 || edge[i].l != edge[i-1].l) j = i + p->line[edge[i].l].numpoints - 1; else j = i - 1; if (edge[j].s <= y ) { /* old edge, remove from active list */ for (m=0; m<nact && active[m]->i!=j; m++); if (m<nact) { nact--; active[m]=active[nact]; } } else if (edge[j].s > y) { /* new edge, insert into active list */ active[nact]= & edge[j]; nact++; } /* vertex next after i */ if(i==nvert-1 || edge[i].l != edge[i+1].l) j = i - p->line[edge[i].l].numpoints + 1; else j = i + 1; if (edge[j].s <= y - 1 ) { /* old edge, remove from active list */ for (m=0; m<nact && active[m]->i!=i; m++); if (m<nact) { nact--; active[m]=active[nact]; } } else if (edge[j].s > y ) { /* new edge, insert into active list */ active[nact]= & edge[i]; nact++; } } /* Sort active edges by x */ do { wrong_order = 0; for(i=0; i < nact-1; i++) { if(active[i]->x > active[i+1]->x) { wrong_order = 1; SWAP(active[i], active[i+1], temp); } } } while(wrong_order); /* draw horizontal spans for scanline y */ for (j=0; j<nact; j+=2) { /* j -> j+1 is inside, j+1 -> j+2 is outside */ xl = (int) MS_NINT(active[j]->x ); xr = (int) (active[j+1]->x - 0.5) ; if(active[j]->x != active[j+1]->x) imageScanline(im, xl, xr, y, c); active[j]->x += active[j]->dx; /* increment edge coords */ active[j+1]->x += active[j+1]->dx; } } free(active); free(edgeindex); free(edge); }
/* ------------------------------------------------------------------------- */ void msDrawShadeSymbolIM(mapObj *map, imageObj* img, shapeObj *p, styleObj *style, double scalefactor) { symbolObj *symbol; int i,j,l; char first = 1; double size; DEBUG_IF printf("msDrawShadeSymbolIM\n<BR>"); if(!p) return; if(p->numlines <= 0) return; symbol = map->symbolset.symbol[style->symbol]; if(style->size == -1) { size = msSymbolGetDefaultSize( symbol ); size = MS_NINT(size*scalefactor); } else size = MS_NINT(style->size*scalefactor); size = MS_MAX(size, style->minsize*img->resolutionfactor); size = MS_MIN(size, style->maxsize*img->resolutionfactor); if (suppressEmpty && p->numvalues==0) return;/* suppress area with empty title */ if(style->symbol == 0) { /* simply draw a single pixel of the specified color // */ for(l=0,j=0; j<p->numlines; j++) { if (dxf == 2) { im_iprintf (&imgStr, "POLY\n%d\n", matchdxfcolor(style->color)); } else if (dxf) { im_iprintf (&imgStr, " 0\nPOLYLINE\n 73\n 1\n 62\n%6d\n 8\n%s\n", matchdxfcolor(style->color), lname); } else { char *title=(p->numvalues) ? p->values[0] : ""; first = 1; im_iprintf (&imgStr, "<area "); if (strcmp(polyHrefFmt,"%.s")!=0) { im_iprintf (&imgStr, "href=\""); im_iprintf (&imgStr, polyHrefFmt, title); im_iprintf (&imgStr, "\" "); } if (strcmp(polyMOverFmt,"%.s")!=0) { im_iprintf (&imgStr, "onMouseOver=\""); im_iprintf (&imgStr, polyMOverFmt, title); im_iprintf (&imgStr, "\" "); } if (strcmp(polyMOutFmt,"%.s")!=0) { im_iprintf (&imgStr, "onMouseOut=\""); im_iprintf (&imgStr, polyMOutFmt, title); im_iprintf (&imgStr, "\" "); } im_iprintf (&imgStr, "title=\"%s\" shape=\"poly\" coords=\"", title); } /* point1 = &( p->line[j].point[p->line[j].numpoints-1] ); */ for(i=0; i < p->line[j].numpoints; i++,l++) { if (dxf == 2) { im_iprintf (&imgStr, "%.0f %.0f\n", p->line[j].point[i].x, p->line[j].point[i].y); } else if (dxf) { im_iprintf (&imgStr, " 0\nVERTEX\n 10\n%f\n 20\n%f\n 30\n%f\n", p->line[j].point[i].x, p->line[j].point[i].y, 0.0); } else { im_iprintf (&imgStr, "%s %.0f,%.0f", first ? "": ",", p->line[j].point[i].x, p->line[j].point[i].y); } first = 0; /* point2 = &( p->line[j].point[i] ); */ /* if(point1->y == point2->y) {} */ } im_iprintf (&imgStr, dxf ? (dxf == 2 ? "": " 0\nSEQEND\n") : "\" />\n"); } return; } /* DEBUG_IF printf ("d"); */ DEBUG_IF printf("-%d-",symbol->type); return; }
int msDrawShadeSymbol(mapObj *map, imageObj *image, shapeObj *p, styleObj *style, double scalefactor) { int ret = MS_SUCCESS; symbolObj *symbol; if (!p) return MS_SUCCESS; if (p->numlines <= 0) return MS_SUCCESS; if (style->symbol >= map->symbolset.numsymbols || style->symbol < 0) return MS_SUCCESS; /* no such symbol, 0 is OK */ symbol = map->symbolset.symbol[style->symbol]; /* * if only an outlinecolor was defined, and not a color, * switch to the line drawing function * * this behavior is kind of a mapfile hack, and must be * kept for backwards compatibility */ if (symbol->type != MS_SYMBOL_PIXMAP && symbol->type != MS_SYMBOL_SVG ) { if (!MS_VALID_COLOR(style->color)) { if(MS_VALID_COLOR(style->outlinecolor)) return msDrawLineSymbol(map, image, p, style, scalefactor); else { /* just do nothing if no color has been set */ return MS_SUCCESS; } } } if (image) { if (MS_RENDERER_PLUGIN(image->format)) { rendererVTableObj *renderer = image->format->vtable; shapeObj *offsetPolygon = NULL; /* store a reference to the renderer to be used for freeing */ if(style->symbol) symbol->renderer = renderer; if (style->offsetx != 0 || style->offsety != 0) { if(style->offsety==MS_STYLE_SINGLE_SIDED_OFFSET) { offsetPolygon = msOffsetPolyline(p, style->offsetx*scalefactor, MS_STYLE_SINGLE_SIDED_OFFSET); } else if(style->offsety==MS_STYLE_DOUBLE_SIDED_OFFSET) { offsetPolygon = msOffsetPolyline(p,style->offsetx * scalefactor ,MS_STYLE_DOUBLE_SIDED_OFFSET); } else { offsetPolygon = msOffsetPolyline(p, style->offsetx*scalefactor,style->offsety*scalefactor); } } else { offsetPolygon=p; } /* simple polygon drawing, without any specific symbol. * also draws an optional outline */ if(style->symbol == 0 || symbol->type == MS_SYMBOL_SIMPLE) { ret = renderer->renderPolygon(image,offsetPolygon,&style->color); if(ret != MS_SUCCESS) goto cleanup; if(MS_VALID_COLOR(style->outlinecolor)) { strokeStyleObj s; INIT_STROKE_STYLE(s); s.color = &style->outlinecolor; s.color->alpha = style->color.alpha; s.width = (style->width == 0)?scalefactor:style->width*scalefactor; s.width = MS_MIN(s.width, style->maxwidth); s.width = MS_MAX(s.width, style->minwidth); ret = renderer->renderLine(image,offsetPolygon,&s); } goto cleanup; /*finished plain polygon*/ } else if(symbol->type == MS_SYMBOL_HATCH) { double width, spacing; double pattern[MS_MAXPATTERNLENGTH]; int i; if(MS_VALID_COLOR(style->backgroundcolor)) { ret = renderer->renderPolygon(image,offsetPolygon, &style->backgroundcolor); if(ret != MS_SUCCESS) goto cleanup; } width = (style->width <= 0)?scalefactor:style->width*scalefactor; width = MS_MIN(width, style->maxwidth*image->resolutionfactor); width = MS_MAX(width, style->minwidth*image->resolutionfactor); spacing = (style->size <= 0)?scalefactor:style->size*scalefactor; spacing = MS_MIN(spacing, style->maxsize*image->resolutionfactor); spacing = MS_MAX(spacing, style->minsize*image->resolutionfactor); /* scale the pattern by the factor applied to the width */ for(i=0; i<style->patternlength; i++) { pattern[i] = style->pattern[i]*width/style->width; } ret = msHatchPolygon(image,offsetPolygon,spacing,width,pattern,style->patternlength,style->angle, &style->color); goto cleanup; } else { symbolStyleObj s; int pw,ph; imageObj *tile; int seamless = 0; if(preloadSymbol(&map->symbolset,symbol,renderer) != MS_SUCCESS) { return MS_FAILURE; } INIT_SYMBOL_STYLE(s); computeSymbolStyle(&s,style,symbol,scalefactor,image->resolutionfactor); s.style = style; if (!s.color && !s.outlinecolor && symbol->type != MS_SYMBOL_PIXMAP && symbol->type != MS_SYMBOL_SVG) { ret = MS_SUCCESS; /* nothing to do (colors are required except for PIXMAP symbols */ goto cleanup; } if(s.backgroundcolor) { ret = renderer->renderPolygon(image,offsetPolygon, s.backgroundcolor); if(ret != MS_SUCCESS) goto cleanup; } if(s.scale != 1) { if (s.gap > 0) { pw = MS_MAX(MS_NINT(s.gap),symbol->sizex * s.scale); ph = MS_MAX(MS_NINT(s.gap),symbol->sizey * s.scale); } else { pw = MS_NINT(symbol->sizex * s.scale); ph = MS_NINT(symbol->sizey * s.scale); } } else { if (s.gap > 0) { pw = MS_MAX(s.gap,symbol->sizex); ph = MS_MAX(s.gap,symbol->sizey); } else { pw = symbol->sizex; ph = symbol->sizey; } } if(pw<1) pw=1; if(ph<1) ph=1; /* if we're doing vector symbols with an antialiased pixel rendererer, we want to enable * seamless mode, i.e. comute a tile that accounts for the blending of neighbouring * tiles at the tile border */ if(symbol->type == MS_SYMBOL_VECTOR && style->gap == 0 && (image->format->renderer == MS_RENDER_WITH_AGG || image->format->renderer == MS_RENDER_WITH_CAIRO_RASTER)) { seamless = 1; } tile = getTile(image,symbol,&s,pw,ph,seamless); ret = renderer->renderPolygonTiled(image,offsetPolygon, tile); } cleanup: if (offsetPolygon != p) { msFreeShape(offsetPolygon); msFree(offsetPolygon); } return ret; } else if( MS_RENDERER_IMAGEMAP(image->format) ) msDrawShadeSymbolIM(map, image, p, style, scalefactor); } return ret; }
int msAddLabel(mapObj *map, labelObj *label, int layerindex, int classindex, shapeObj *shape, pointObj *point, labelPathObj *labelpath, double featuresize) { int i; labelCacheSlotObj *cacheslot; labelCacheMemberObj *cachePtr=NULL; layerObj *layerPtr=NULL; classObj *classPtr=NULL; if(!label) return(MS_FAILURE); // RFC 77 TODO: set a proper message if(label->status == MS_OFF) return(MS_SUCCESS); /* not an error */ if(!label->annotext) { /* check if we have a labelpnt style */ for(i=0; i<label->numstyles; i++) { if(label->styles[i]->_geomtransform.type == MS_GEOMTRANSFORM_LABELPOINT) break; } if(i==label->numstyles) { /* label has no text or marker symbols */ return MS_SUCCESS; } } layerPtr = (GET_LAYER(map, layerindex)); /* set up a few pointers for clarity */ classPtr = GET_LAYER(map, layerindex)->class[classindex]; if(classPtr->leader.maxdistance) { if (layerPtr->type == MS_LAYER_ANNOTATION) { msSetError(MS_MISCERR, "LEADERs are not supported on annotation layers", "msAddLabel()"); return MS_FAILURE; } if(labelpath) { msSetError(MS_MISCERR, "LEADERs are not supported on ANGLE FOLLOW labels", "msAddLabel()"); return MS_FAILURE; } } /* check that the label intersects the layer mask */ if (layerPtr->mask) { int maskLayerIdx = msGetLayerIndex(map, layerPtr->mask); layerObj *maskLayer = GET_LAYER(map, maskLayerIdx); unsigned char *alphapixptr; if (maskLayer->maskimage && MS_IMAGE_RENDERER(maskLayer->maskimage)->supports_pixel_buffer) { rasterBufferObj rb; memset(&rb, 0, sizeof (rasterBufferObj)); MS_IMAGE_RENDERER(maskLayer->maskimage)->getRasterBufferHandle(maskLayer->maskimage, &rb); if (point) { int x = MS_NINT(point->x); int y = MS_NINT(point->y); /* Using label repeatdistance, we might have a point with x/y below 0. See #4764 */ if (x >= 0 && x < rb.width && y >= 0 && y < rb.height) { #ifdef USE_GD if(rb.type == MS_BUFFER_BYTE_RGBA) { alphapixptr = rb.data.rgba.a+rb.data.rgba.row_step*y + rb.data.rgba.pixel_step*x; if(!*alphapixptr) { /* label point does not intersect mask */ return MS_SUCCESS; } } else { if(!gdImageGetPixel(rb.data.gd_img,x,y)) { return MS_SUCCESS; } } #else assert(rb.type == MS_BUFFER_BYTE_RGBA); alphapixptr = rb.data.rgba.a+rb.data.rgba.row_step*y + rb.data.rgba.pixel_step*x; if(!*alphapixptr) { /* label point does not intersect mask */ return MS_SUCCESS; } #endif } } else if (labelpath) { int i = 0; for (i = 0; i < labelpath->path.numpoints; i++) { int x = MS_NINT(labelpath->path.point[i].x); int y = MS_NINT(labelpath->path.point[i].y); /* Using label repeatdistance, we might have a point with x/y below 0. See #4764 */ if (x >= 0 && x < rb.width && y >= 0 && y < rb.height) { #ifdef USE_GD if (rb.type == MS_BUFFER_BYTE_RGBA) { alphapixptr = rb.data.rgba.a + rb.data.rgba.row_step * y + rb.data.rgba.pixel_step*x; if (!*alphapixptr) { /* label point does not intersect mask */ msFreeLabelPathObj(labelpath); return MS_SUCCESS; } } else { if (!gdImageGetPixel(rb.data.gd_img, x, y)) { msFreeLabelPathObj(labelpath); return MS_SUCCESS; } } #else assert(rb.type == MS_BUFFER_BYTE_RGBA); alphapixptr = rb.data.rgba.a + rb.data.rgba.row_step * y + rb.data.rgba.pixel_step*x; if (!*alphapixptr) { /* label point does not intersect mask */ msFreeLabelPathObj(labelpath); return MS_SUCCESS; } #endif } } } } else { msSetError(MS_MISCERR, "Layer (%s) references references a mask layer, but the selected renderer does not support them", "msAddLabel()", layerPtr->name); return (MS_FAILURE); } } /* Validate label priority value and get ref on label cache for it */ if (label->priority < 1) label->priority = 1; else if (label->priority > MS_MAX_LABEL_PRIORITY) label->priority = MS_MAX_LABEL_PRIORITY; cacheslot = &(map->labelcache.slots[label->priority-1]); if(cacheslot->numlabels == cacheslot->cachesize) { /* just add it to the end */ cacheslot->labels = (labelCacheMemberObj *) realloc(cacheslot->labels, sizeof(labelCacheMemberObj)*(cacheslot->cachesize+MS_LABELCACHEINCREMENT)); MS_CHECK_ALLOC(cacheslot->labels, sizeof(labelCacheMemberObj)*(cacheslot->cachesize+MS_LABELCACHEINCREMENT), MS_FAILURE); cacheslot->cachesize += MS_LABELCACHEINCREMENT; } cachePtr = &(cacheslot->labels[cacheslot->numlabels]); cachePtr->layerindex = layerindex; /* so we can get back to this *raw* data if necessary */ cachePtr->classindex = classindex; if(shape) { cachePtr->shapetype = shape->type; } else { cachePtr->shapetype = MS_SHAPE_POINT; } cachePtr->leaderline = NULL; cachePtr->leaderbbox = NULL; /* Store the label point or the label path (Bug #1620) */ if ( point ) { cachePtr->point = *point; /* the actual label point */ cachePtr->labelpath = NULL; } else { assert(labelpath); cachePtr->labelpath = labelpath; /* Use the middle point of the labelpath for mindistance calculations */ cachePtr->point = labelpath->path.point[labelpath->path.numpoints / 2]; } /* TODO: perhaps we can get rid of this next section and just store a marker size? Why do we cache the styles for a point layer? */ /* copy the styles (only if there is an accompanying marker) * We cannot simply keeep refs because the rendering code alters some members of the style objects */ cachePtr->styles = NULL; cachePtr->numstyles = 0; if(layerPtr->type == MS_LAYER_ANNOTATION && classPtr->numstyles > 0) { cachePtr->numstyles = classPtr->numstyles; cachePtr->styles = (styleObj *) msSmallMalloc(sizeof(styleObj)*classPtr->numstyles); if (classPtr->numstyles > 0) { for(i=0; i<classPtr->numstyles; i++) { initStyle(&(cachePtr->styles[i])); msCopyStyle(&(cachePtr->styles[i]), classPtr->styles[i]); } } } /* copy the label */ cachePtr->numlabels = 1; cachePtr->labels = (labelObj *) msSmallMalloc(sizeof(labelObj)); initLabel(cachePtr->labels); msCopyLabel(cachePtr->labels, label); cachePtr->markerid = -1; cachePtr->featuresize = featuresize; //cachePtr->poly = (shapeObj *) msSmallMalloc(sizeof(shapeObj)); //msInitShape(cachePtr->poly); cachePtr->poly = NULL; cachePtr->status = MS_FALSE; if(layerPtr->type == MS_LAYER_POINT && classPtr->numstyles > 0) { /* cache the marker placement, it's already on the map */ rectObj rect; double w, h; if(cacheslot->nummarkers == cacheslot->markercachesize) { /* just add it to the end */ cacheslot->markers = (markerCacheMemberObj *) realloc(cacheslot->markers, sizeof(markerCacheMemberObj)*(cacheslot->cachesize+MS_LABELCACHEINCREMENT)); MS_CHECK_ALLOC(cacheslot->markers, sizeof(markerCacheMemberObj)*(cacheslot->cachesize+MS_LABELCACHEINCREMENT), MS_FAILURE); cacheslot->markercachesize+=MS_LABELCACHEINCREMENT; } i = cacheslot->nummarkers; cacheslot->markers[i].poly = (shapeObj *) msSmallMalloc(sizeof(shapeObj)); msInitShape(cacheslot->markers[i].poly); /* TO DO: at the moment only checks the bottom style, perhaps should check all of them */ /* #2347: after RFC-24 classPtr->styles could be NULL so we check it */ if(classPtr->styles != NULL) { if(msGetMarkerSize(&map->symbolset, classPtr->styles[0], &w, &h, layerPtr->scalefactor) != MS_SUCCESS) return(MS_FAILURE); rect.minx = point->x - .5 * w; rect.miny = point->y - .5 * h; rect.maxx = rect.minx + (w-1); rect.maxy = rect.miny + (h-1); msRectToPolygon(rect, cacheslot->markers[i].poly); cacheslot->markers[i].id = cacheslot->numlabels; cachePtr->markerid = i; cacheslot->nummarkers++; } } cacheslot->numlabels++; /* Maintain main labelCacheObj.numlabels only for backwards compatibility */ map->labelcache.numlabels++; return(MS_SUCCESS); }
int msApplyCompositingFilter(mapObj *map, rasterBufferObj *rb, CompositingFilter *filter) { int rstatus; regex_t regex; regmatch_t pmatch[3]; /* test for blurring filter */ regcomp(®ex, "blur\\(([0-9]+)\\)", REG_EXTENDED); rstatus = regexec(®ex, filter->filter, 2, pmatch, 0); regfree(®ex); if(!rstatus) { char *rad = malloc(pmatch[1].rm_eo - pmatch[1].rm_so + 1); unsigned int irad; strncpy(rad,filter->filter+pmatch[1].rm_so,pmatch[1].rm_eo-pmatch[1].rm_so); rad[pmatch[1].rm_eo - pmatch[1].rm_so]=0; //msDebug("got blur filter with radius %s\n",rad); irad = atoi(rad); free(rad); irad = MS_NINT(irad*map->resolution/map->defresolution); msApplyBlurringCompositingFilter(rb,irad); return MS_SUCCESS; } /* test for translation filter */ regcomp(®ex, "translate\\((-?[0-9]+),(-?[0-9]+)\\)", REG_EXTENDED); rstatus = regexec(®ex, filter->filter, 3, pmatch, 0); regfree(®ex); if(!rstatus) { char *num; int xtrans,ytrans; num = malloc(pmatch[1].rm_eo - pmatch[1].rm_so + 1); strncpy(num,filter->filter+pmatch[1].rm_so,pmatch[1].rm_eo-pmatch[1].rm_so); num[pmatch[1].rm_eo - pmatch[1].rm_so]=0; xtrans = atoi(num); free(num); num = malloc(pmatch[2].rm_eo - pmatch[2].rm_so + 1); strncpy(num,filter->filter+pmatch[2].rm_so,pmatch[2].rm_eo-pmatch[2].rm_so); num[pmatch[2].rm_eo - pmatch[2].rm_so]=0; ytrans = atoi(num); free(num); //msDebug("got translation filter of radius %d,%d\n",xtrans,ytrans); xtrans = MS_NINT(xtrans*map->resolution/map->defresolution); ytrans = MS_NINT(ytrans*map->resolution/map->defresolution); msApplyTranslationCompositingFilter(rb,xtrans,ytrans); return MS_SUCCESS; } /* test for grayscale filter */ if(!strncmp(filter->filter,"grayscale()",strlen("grayscale()"))) { msApplyGrayscaleCompositingFilter(rb); return MS_SUCCESS; } if(!strncmp(filter->filter,"blacken()",strlen("blacken()"))) { msApplyBlackeningCompositingFilter(rb); return MS_SUCCESS; } if(!strncmp(filter->filter,"whiten()",strlen("whiten()"))) { msApplyWhiteningCompositingFilter(rb); return MS_SUCCESS; } msSetError(MS_MISCERR,"unknown compositing filter (%s)", "msApplyCompositingFilter()", filter->filter); return MS_FAILURE; }
const char* KmlRenderer::lookupPlacemarkStyle() { char lineHexColor[32]; char polygonHexColor[32]; char labelHexColor[32]; char *styleName=NULL; styleName = msStringConcatenate(styleName, "style"); if (SymbologyFlag[Line]) { /* <LineStyle id="ID"> <!-- inherited from ColorStyle --> <color>ffffffff</color> <!-- kml:color --> <colorMode>normal</colorMode> <!-- colorModeEnum: normal or random --> <!-- specific to LineStyle --> <width>1</width> <!-- float --> </LineStyle> */ for (int i=0; i<numLineStyle; i++) { if (currentLayer && currentLayer->compositer && currentLayer->compositer->opacity > 0 && currentLayer->compositer->opacity < 100 && LineStyle[i].color->alpha == 255) LineStyle[i].color->alpha = MS_NINT(currentLayer->compositer->opacity*2.55); sprintf(lineHexColor,"%02x%02x%02x%02x", LineStyle[i].color->alpha, LineStyle[0].color->blue, LineStyle[i].color->green, LineStyle[i].color->red); char lineStyleName[32]; sprintf(lineStyleName, "_line_%s_w%.1f", lineHexColor, LineStyle[i].width); styleName = msStringConcatenate(styleName, lineStyleName); } } if (SymbologyFlag[Polygon]) { /* <PolyStyle id="ID"> <!-- inherited from ColorStyle --> <color>ffffffff</color> <!-- kml:color --> <colorMode>normal</colorMode> <!-- kml:colorModeEnum: normal or random --> <!-- specific to PolyStyle --> <fill>1</fill> <!-- boolean --> <outline>1</outline> <!-- boolean --> </PolyStyle> */ if (currentLayer && currentLayer->compositer && currentLayer->compositer->opacity > 0 && currentLayer->compositer->opacity < 100 && PolygonColor.alpha == 255) PolygonColor.alpha = MS_NINT(currentLayer->compositer->opacity*2.55); sprintf(polygonHexColor,"%02x%02x%02x%02x", PolygonColor.alpha, PolygonColor.blue, PolygonColor.green, PolygonColor.red); char polygonStyleName[64]; sprintf(polygonStyleName, "_polygon_%s", polygonHexColor); styleName = msStringConcatenate(styleName, polygonStyleName); } if (SymbologyFlag[Label]) { /* <LabelStyle id="ID"> <!-- inherited from ColorStyle --> <color>ffffffff</color> <!-- kml:color --> <colorMode>normal</colorMode> <!-- kml:colorModeEnum: normal or random --> <!-- specific to LabelStyle --> <scale>1</scale> <!-- float --> </LabelStyle> */ if (currentLayer && currentLayer->compositer && currentLayer->compositer->opacity > 0 && currentLayer->compositer->opacity < 100 && LabelColor.alpha == 255) LabelColor.alpha = MS_NINT(currentLayer->compositer->opacity*2.55); sprintf(labelHexColor,"%02x%02x%02x%02x", LabelColor.alpha, LabelColor.blue, LabelColor.green, LabelColor.red); // __TODO__ add label scale char labelStyleName[64]; sprintf(labelStyleName, "_label_%s", labelHexColor); styleName = msStringConcatenate(styleName, labelStyleName); } if (SymbologyFlag[Symbol]) { /* <Style id="randomColorIcon"> <IconStyle> <color>ff00ff00</color> <colorMode>random</colorMode> <scale>1.1</scale> <Icon> <href>http://maps.google.com/mapfiles/kml/pal3/icon21.png</href> </Icon> </IconStyle> </Style> */ /* __TODO__ add label scale */ styleName = msStringConcatenate(styleName, "_"); styleName = msStringConcatenate(styleName, SymbolName); } const char *styleUrl = msLookupHashTable(StyleHashTable, styleName); if (!styleUrl) { char *styleValue=NULL; styleValue = msStringConcatenate(styleValue, "#"); styleValue = msStringConcatenate(styleValue, styleName); hashObj *hash = msInsertHashTable(StyleHashTable, styleName, styleValue); styleUrl = hash->data; msFree(styleValue); /* Insert new Style node into Document node*/ xmlNodePtr styleNode = xmlNewChild(DocNode, NULL, BAD_CAST "Style", NULL); xmlNewProp(styleNode, BAD_CAST "id", BAD_CAST styleName); if (SymbologyFlag[Polygon]) { xmlNodePtr polyStyleNode = xmlNewChild(styleNode, NULL, BAD_CAST "PolyStyle", NULL); xmlNewChild(polyStyleNode, NULL, BAD_CAST "color", BAD_CAST polygonHexColor); } if (SymbologyFlag[Line]) { for (int i=0; i<numLineStyle; i++) { xmlNodePtr lineStyleNode = xmlNewChild(styleNode, NULL, BAD_CAST "LineStyle", NULL); sprintf(lineHexColor,"%02x%02x%02x%02x", LineStyle[i].color->alpha, LineStyle[i].color->blue, LineStyle[i].color->green, LineStyle[i].color->red); xmlNewChild(lineStyleNode, NULL, BAD_CAST "color", BAD_CAST lineHexColor); char width[16]; sprintf(width, "%.1f", LineStyle[i].width); xmlNewChild(lineStyleNode, NULL, BAD_CAST "width", BAD_CAST width); } } if (SymbologyFlag[Symbol]) { xmlNodePtr iconStyleNode = xmlNewChild(styleNode, NULL, BAD_CAST "IconStyle", NULL); xmlNodePtr iconNode = xmlNewChild(iconStyleNode, NULL, BAD_CAST "Icon", NULL); xmlNewChild(iconNode, NULL, BAD_CAST "href", BAD_CAST SymbolUrl); /*char scale[16]; sprintf(scale, "%.1f", style->scale); xmlNewChild(iconStyleNode, NULL, BAD_CAST "scale", BAD_CAST scale);*/ } else { const char *value=msLookupHashTable(¤tLayer->metadata, "kml_default_symbol_href"); if (value && strlen(value) > 0) { xmlNodePtr iconStyleNode = xmlNewChild(styleNode, NULL, BAD_CAST "IconStyle", NULL); xmlNodePtr iconNode = xmlNewChild(iconStyleNode, NULL, BAD_CAST "Icon", NULL); xmlNewChild(iconNode, NULL, BAD_CAST "href", BAD_CAST value); } } if (SymbologyFlag[Label]) { xmlNodePtr labelStyleNode = xmlNewChild(styleNode, NULL, BAD_CAST "LabelStyle", NULL); xmlNewChild(labelStyleNode, NULL, BAD_CAST "color", BAD_CAST labelHexColor); /*char scale[16]; sprintf(scale, "%.1f", style->scale); xmlNewChild(iconStyleNode, NULL, BAD_CAST "scale", BAD_CAST scale);*/ } } if (styleName) msFree(styleName); return styleUrl; }