template<class VertexSource> int renderPolygonHatches(imageObj *img,VertexSource &clipper, colorObj *color) { if(img->format->renderer == MS_RENDER_WITH_AGG) { AGG2Renderer *r = AGG_RENDERER(img); r->m_rasterizer_aa_gamma.reset(); r->m_rasterizer_aa_gamma.filling_rule(mapserver::fill_non_zero); r->m_rasterizer_aa_gamma.add_path(clipper); r->m_renderer_scanline.color(aggColor(color)); mapserver::render_scanlines(r->m_rasterizer_aa_gamma, r->sl_poly, r->m_renderer_scanline); } else { shapeObj shape; msInitShape(&shape); int allocated = 20; lineObj line; shape.line = &line; shape.numlines = 1; shape.line[0].point = (pointObj*)msSmallCalloc(allocated,sizeof(pointObj)); shape.line[0].numpoints = 0; double x=0,y=0; unsigned int cmd; clipper.rewind(0); while((cmd = clipper.vertex(&x,&y)) != mapserver::path_cmd_stop) { switch(cmd) { case mapserver::path_cmd_line_to: if(shape.line[0].numpoints == allocated) { allocated *= 2; shape.line[0].point = (pointObj*)msSmallRealloc(shape.line[0].point, allocated*sizeof(pointObj)); } shape.line[0].point[shape.line[0].numpoints].x = x; shape.line[0].point[shape.line[0].numpoints].y = y; shape.line[0].numpoints++; break; case mapserver::path_cmd_move_to: shape.line[0].point[0].x = x; shape.line[0].point[0].y = y; shape.line[0].numpoints = 1; break; case mapserver::path_cmd_end_poly|mapserver::path_flags_close: if(shape.line[0].numpoints > 2) { if(UNLIKELY(MS_FAILURE == MS_IMAGE_RENDERER(img)->renderPolygon(img,&shape,color))) { free(shape.line[0].point); return MS_FAILURE; } } break; default: assert(0); //WTF? } } free(shape.line[0].point); } return MS_SUCCESS; }
int agg2RenderTruetypeSymbol(imageObj *img, double x, double y, symbolObj *symbol, symbolStyleObj * style) { AGG2Renderer *r = AGG_RENDERER(img); aggRendererCache *cache = (aggRendererCache*)MS_RENDERER_CACHE(MS_IMAGE_RENDERER(img)); if(aggLoadFont(cache,symbol->full_font_path,style->scale) == MS_FAILURE) return MS_FAILURE; int unicode; font_curve_type m_curves(cache->m_fman.path_adaptor()); msUTF8ToUniChar(symbol->character, &unicode); const mapserver::glyph_cache* glyph = cache->m_fman.glyph(unicode); double ox = (glyph->bounds.x1 + glyph->bounds.x2) / 2.; double oy = (glyph->bounds.y1 + glyph->bounds.y2) / 2.; mapserver::trans_affine mtx = mapserver::trans_affine_translation(-ox, -oy); if(style->rotation) mtx *= mapserver::trans_affine_rotation(-style->rotation); mtx *= mapserver::trans_affine_translation(x, y); mapserver::path_storage glyphs; cache->m_fman.init_embedded_adaptors(glyph, 0,0); mapserver::conv_transform<font_curve_type, mapserver::trans_affine> trans_c(m_curves, mtx); glyphs.concat_path(trans_c); if (style->outlinecolor) { r->m_rasterizer_aa.reset(); r->m_rasterizer_aa.filling_rule(mapserver::fill_non_zero); mapserver::conv_contour<mapserver::path_storage> cc(glyphs); cc.auto_detect_orientation(true); cc.width(style->outlinewidth + 1); r->m_rasterizer_aa.add_path(cc); r->m_renderer_scanline.color(aggColor(style->outlinecolor)); mapserver::render_scanlines(r->m_rasterizer_aa, r->sl_line, r->m_renderer_scanline); } if (style->color) { r->m_rasterizer_aa.reset(); r->m_rasterizer_aa.filling_rule(mapserver::fill_non_zero); r->m_rasterizer_aa.add_path(glyphs); r->m_renderer_scanline.color(aggColor(style->color)); mapserver::render_scanlines(r->m_rasterizer_aa, r->sl_line, r->m_renderer_scanline); } 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; }
/* * 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; }
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 }
void msWriteErrorImage(mapObj *map, char *filename, int blank) { imageObj *img; rendererVTableObj *renderer; int font_index = 0; int width=400, height=300; int nMargin =5; int nTextLength = 0; int nUsableWidth = 0; int nMaxCharsPerLine = 0; int nLines = 0; int i = 0; int nStart = 0; int nEnd = 0; int nLength = 0; char **papszLines = NULL; int nXPos = 0; int nYPos = 0; int nWidthTxt = 0; outputFormatObj *format = NULL; char *errormsg = msGetErrorString("; "); fontMetrics *font = NULL; char *imagepath = NULL, *imageurl = NULL; labelStyleObj ls; colorObj labelcolor, labeloutlinecolor, imagecolor, *imagecolorptr=NULL; ls.color = &labelcolor; ls.outlinecolor = &labeloutlinecolor; if (map) { if( map->width > 0 && map->height > 0 ) { width = map->width; height = map->height; } format = map->outputformat; imagepath = map->web.imagepath; imageurl = map->web.imageurl; } /* Default to GIF if no suitable GD output format set */ if (format == NULL || !MS_RENDERER_PLUGIN(format) || !format->vtable->supports_bitmap_fonts) format = msCreateDefaultOutputFormat( NULL, "GD/PC256", "gif" ); if(!format->transparent) { if(map && MS_VALID_COLOR(map->imagecolor)) { imagecolorptr = &map->imagecolor; } else { MS_INIT_COLOR(imagecolor,255,255,255,255); imagecolorptr = &imagecolor; } } img = msImageCreate(width,height,format,imagepath,imageurl,MS_DEFAULT_RESOLUTION,MS_DEFAULT_RESOLUTION,imagecolorptr); renderer = MS_IMAGE_RENDERER(img); for(i=0; i<5; i++) { /* use the first font we find */ if((font = renderer->bitmapFontMetrics[font_index]) != NULL) { ls.size = i; MS_INIT_COLOR(*ls.color,0,0,0,255); MS_INIT_COLOR(*ls.outlinecolor,255,255,255,255); break; } } /* if no font found we can't do much. this shouldn't happen */ if(font) { nTextLength = strlen(errormsg); nWidthTxt = nTextLength * font->charWidth; nUsableWidth = width - (nMargin*2); /* Check to see if it all fits on one line. If not, split the text on several lines. */ if(!blank) { if (nWidthTxt > nUsableWidth) { nMaxCharsPerLine = nUsableWidth/font->charWidth; nLines = (int) ceil ((double)nTextLength / (double)nMaxCharsPerLine); if (nLines > 0) { papszLines = (char **)malloc(nLines*sizeof(char *)); for (i=0; i<nLines; i++) { papszLines[i] = (char *)malloc((nMaxCharsPerLine+1)*sizeof(char)); papszLines[i][0] = '\0'; } } for (i=0; i<nLines; i++) { nStart = i*nMaxCharsPerLine; nEnd = nStart + nMaxCharsPerLine; if (nStart < nTextLength) { if (nEnd > nTextLength) nEnd = nTextLength; nLength = nEnd-nStart; strncpy(papszLines[i], errormsg+nStart, nLength); papszLines[i][nLength] = '\0'; } } } else { nLines = 1; papszLines = (char **)malloc(nLines*sizeof(char *)); papszLines[0] = msStrdup(errormsg); } for (i=0; i<nLines; i++) { nYPos = (font->charHeight) * ((i*2) +1); nXPos = font->charWidth;; renderer->renderBitmapGlyphs(img, nXPos, nYPos, &ls, papszLines[i]); } if (papszLines) { for (i=0; i<nLines; i++) { free(papszLines[i]); } free(papszLines); } } } /* actually write the image */ if(!filename) { msIO_setHeader("Content-type","%s", MS_IMAGE_MIME_TYPE(format)); msIO_sendHeaders(); } msSaveImage(NULL,img,filename); msFreeImage(img); if (format->refcount == 0) msFreeOutputFormat(format); msFree(errormsg); }
int msImagePolylineMarkers(imageObj *image, shapeObj *p, symbolObj *symbol, symbolStyleObj *style, double spacing, double initialgap, int auto_angle) { rendererVTableObj *renderer = MS_IMAGE_RENDERER(image); int i,j; pointObj point; double original_rotation = style->rotation; double symbol_width,symbol_height; glyph_element *glyphc = NULL; face_element *face; int ret = MS_SUCCESS; if(symbol->type != MS_SYMBOL_TRUETYPE) { symbol_width = MS_MAX(1,symbol->sizex*style->scale); symbol_height = MS_MAX(1,symbol->sizey*style->scale); } else { unsigned int unicode; msUTF8ToUniChar(symbol->character, &unicode); face = msGetFontFace(symbol->font, &image->map->fontset); if(UNLIKELY(!face)) return MS_FAILURE; unicode = msGetGlyphIndex(face,unicode); glyphc = msGetGlyphByIndex(face, style->scale, unicode); if(UNLIKELY(!glyphc)) return MS_FAILURE; symbol_width = glyphc->metrics.maxx - glyphc->metrics.minx; symbol_height = glyphc->metrics.maxy - glyphc->metrics.miny; } for(i=0; i<p->numlines; i++) { int line_in = 0; double line_length=0; double current_length; if(initialgap < 0) { current_length = spacing/2.0; /* initial padding for each line */ } else { current_length = initialgap; /* initial padding for each line */ } for(j=1; j<p->line[i].numpoints; j++) { double rx,ry,theta,length; length = sqrt((pow((p->line[i].point[j].x - p->line[i].point[j-1].x),2) + pow((p->line[i].point[j].y - p->line[i].point[j-1].y),2))); line_length += length; if(length==0)continue; rx = (p->line[i].point[j].x - p->line[i].point[j-1].x)/length; ry = (p->line[i].point[j].y - p->line[i].point[j-1].y)/length; if (auto_angle) { theta = asin(ry); if(rx < 0) { theta += MS_PI; } else theta = -theta; style->rotation = original_rotation + theta; } while (current_length <= length) { point.x = p->line[i].point[j - 1].x + current_length * rx; point.y = p->line[i].point[j - 1].y + current_length * ry; if(symbol->anchorpoint_x != 0.5 || symbol->anchorpoint_y != 0.5) { double ox, oy; ox = (0.5 - symbol->anchorpoint_x) * symbol_width; oy = (0.5 - symbol->anchorpoint_y) * symbol_height; if(style->rotation != 0) { double sina,cosa; double rox,roy; sina = sin(-style->rotation); cosa = cos(-style->rotation); rox = ox * cosa - oy * sina; roy = ox * sina + oy * cosa; point.x += rox; point.y += roy; } else { point.x += ox; point.y += oy; } } /* if the point is not in the map extent, skip it. (POLYLINE_NO_CLIP) */ if ( (point.x < -(symbol_width) || point.x > (image->width+symbol_width)) || (point.y < -(symbol_height) || point.y > (image->height+symbol_height)) ) { current_length += spacing; line_in=1; continue; } switch (symbol->type) { case MS_SYMBOL_PIXMAP: ret = renderer->renderPixmapSymbol(image, point.x, point.y, symbol, style); break; case MS_SYMBOL_ELLIPSE: ret = renderer->renderEllipseSymbol(image, point.x, point.y, symbol, style); break; case MS_SYMBOL_VECTOR: ret = renderer->renderVectorSymbol(image, point.x, point.y, symbol, style); break; case MS_SYMBOL_TRUETYPE: ret = drawGlyphMarker(image, face, glyphc, point.x, point.y, style->scale, style->rotation, style->color, style->outlinecolor, style->outlinewidth); break; case (MS_SYMBOL_SVG): #if defined(USE_SVG_CAIRO) || defined(USE_RSVG) if (renderer->supports_svg) { ret = renderer->renderSVGSymbol(image, point.x, point.y, symbol, style); } else { ret = msRenderRasterizedSVGSymbol(image,point.x,point.y,symbol, style); } #else msSetError(MS_SYMERR, "SVG symbol support is not enabled.", "msImagePolylineMarkers()()"); ret = MS_FAILURE; #endif break; } if( ret != MS_SUCCESS) return ret; current_length += spacing; line_in=1; } current_length -= length; } /* * if we couldn't place a symbol on the line and no initialgap was * specified, add one now we don't add the symbol if the line is shorter * than the length of the symbol itself */ if(initialgap < 0 && !line_in && line_length>symbol_width) { /* total lengths of beginnning and end of current segment */ double before_length=0,after_length=0; /*optimize*/ line_length /= 2.0; for(j=1; j<p->line[i].numpoints; j++) { double length; length = sqrt((pow((p->line[i].point[j].x - p->line[i].point[j-1].x),2) + pow((p->line[i].point[j].y - p->line[i].point[j-1].y),2))); after_length += length; if(after_length>line_length) { double rx,ry,theta; /* offset where the symbol should be drawn on the current * segment */ double offset = line_length - before_length; rx = (p->line[i].point[j].x - p->line[i].point[j-1].x)/length; ry = (p->line[i].point[j].y - p->line[i].point[j-1].y)/length; if (auto_angle) { theta = asin(ry); if(rx < 0) { theta += MS_PI; } else theta = -theta; style->rotation = original_rotation + theta; } point.x = p->line[i].point[j - 1].x + offset * rx; point.y = p->line[i].point[j - 1].y + offset * ry; switch (symbol->type) { case MS_SYMBOL_PIXMAP: ret = renderer->renderPixmapSymbol(image, point.x, point.y, symbol, style); break; case MS_SYMBOL_ELLIPSE: ret = renderer->renderEllipseSymbol(image, point.x, point.y, symbol, style); break; case MS_SYMBOL_VECTOR: ret = renderer->renderVectorSymbol(image, point.x, point.y, symbol, style); break; case MS_SYMBOL_TRUETYPE: ret = drawGlyphMarker(image, face, glyphc, point.x, point.y, style->scale, style->rotation, style->color, style->outlinecolor, style->outlinewidth); break; case (MS_SYMBOL_SVG): #if defined(USE_SVG_CAIRO) || defined(USE_RSVG) if (renderer->supports_svg) { ret = renderer->renderSVGSymbol(image, point.x, point.y, symbol, style); } else { ret = msRenderRasterizedSVGSymbol(image,point.x,point.y,symbol, style); } #else msSetError(MS_SYMERR, "SVG symbol support is not enabled.", "msImagePolylineMarkers()()"); ret = MS_FAILURE; #endif break; } break; /* we have rendered the single marker for this line */ } before_length += length; } } } return ret; }
imageObj *getTile(imageObj *img, symbolObj *symbol, symbolStyleObj *s, int width, int height, int seamlessmode) { tileCacheObj *tile; int status = MS_SUCCESS; rendererVTableObj *renderer = img->format->vtable; if(width==-1 || height == -1) { width=height=MS_MAX(symbol->sizex,symbol->sizey); } tile = searchTileCache(img,symbol,s,width,height); if(tile==NULL) { imageObj *tileimg; double p_x,p_y; tileimg = msImageCreate(width,height,img->format,NULL,NULL,img->resolution, img->resolution, NULL); if(UNLIKELY(!tileimg)) { return NULL; } if(!seamlessmode) { p_x = width/2.0; p_y = height/2.0; switch(symbol->type) { case (MS_SYMBOL_TRUETYPE): { unsigned int unicode; glyph_element *glyphc; face_element *face = msGetFontFace(symbol->font, &img->map->fontset); if(UNLIKELY(!face)) { status = MS_FAILURE; break; } msUTF8ToUniChar(symbol->character, &unicode); unicode = msGetGlyphIndex(face,unicode); glyphc = msGetGlyphByIndex(face, s->scale, unicode); if(UNLIKELY(!face)) { status = MS_FAILURE; break; } status = drawGlyphMarker(tileimg, face, glyphc, p_x, p_y, s->scale, s->rotation, s->color, s->outlinecolor, s->outlinewidth); } break; case (MS_SYMBOL_PIXMAP): status = msPreloadImageSymbol(renderer,symbol); if(UNLIKELY(status == MS_FAILURE)) { break; } status = renderer->renderPixmapSymbol(tileimg, p_x, p_y, symbol, s); break; case (MS_SYMBOL_ELLIPSE): status = renderer->renderEllipseSymbol(tileimg, p_x, p_y,symbol, s); break; case (MS_SYMBOL_VECTOR): status = renderer->renderVectorSymbol(tileimg, p_x, p_y, symbol, s); break; case (MS_SYMBOL_SVG): #if defined(USE_SVG_CAIRO) || defined(USE_RSVG) status = msPreloadSVGSymbol(symbol); if(LIKELY(status == MS_SUCCESS)) { if (renderer->supports_svg) { status = renderer->renderSVGSymbol(tileimg, p_x, p_y, symbol, s); } else { status = msRenderRasterizedSVGSymbol(tileimg,p_x,p_y,symbol, s); } } #else msSetError(MS_SYMERR, "SVG symbol support is not enabled.", "getTile()"); status = MS_FAILURE; #endif break; default: msSetError(MS_SYMERR, "Unknown symbol type %d", "getTile()", symbol->type); status = MS_FAILURE; break; } if(UNLIKELY(status == MS_FAILURE)) { msFreeImage(tileimg); return NULL; } } else { /* * in seamless mode, we render the the symbol 9 times on a 3x3 grid to account for * antialiasing blending from one tile to the next. We finally keep the center tile */ imageObj *tile3img = msImageCreate(width*3,height*3,img->format,NULL,NULL, img->resolution, img->resolution, NULL); int i,j; rasterBufferObj tmpraster; for(i=1; i<=3; i++) { p_x = (i+0.5)*width; for(j=1; j<=3; j++) { p_y = (j+0.5) * height; switch(symbol->type) { case (MS_SYMBOL_TRUETYPE): { unsigned int unicode; glyph_element *glyphc; face_element *face = msGetFontFace(symbol->font, &img->map->fontset); if(UNLIKELY(!face)) { status = MS_FAILURE; break; } msUTF8ToUniChar(symbol->character, &unicode); unicode = msGetGlyphIndex(face,unicode); glyphc = msGetGlyphByIndex(face, s->scale, unicode); if(UNLIKELY(!glyphc)) { status = MS_FAILURE; break; } status = drawGlyphMarker(tileimg, face, glyphc, p_x, p_y, s->scale, s->rotation, s->color, s->outlinecolor, s->outlinewidth); } break; case (MS_SYMBOL_PIXMAP): status = msPreloadImageSymbol(renderer,symbol); if(UNLIKELY(status == MS_FAILURE)) { break; } status = renderer->renderPixmapSymbol(tile3img, p_x, p_y, symbol, s); break; case (MS_SYMBOL_ELLIPSE): status = renderer->renderEllipseSymbol(tile3img, p_x, p_y,symbol, s); break; case (MS_SYMBOL_VECTOR): status = renderer->renderVectorSymbol(tile3img, p_x, p_y, symbol, s); break; default: msSetError(MS_SYMERR, "BUG: Seamless mode is only for vector symbols", "getTile()"); return NULL; } if(UNLIKELY(status == MS_FAILURE)) { msFreeImage(tile3img); return NULL; } } } if(UNLIKELY(status == MS_FAILURE)) { msFreeImage(tile3img); return NULL; } status = MS_IMAGE_RENDERER(tile3img)->getRasterBufferHandle(tile3img,&tmpraster); if(UNLIKELY(status == MS_FAILURE)) { msFreeImage(tile3img); return NULL; } status = renderer->mergeRasterBuffer(tileimg, &tmpraster, 1.0,width,height,0,0,width,height ); msFreeImage(tile3img); } if(UNLIKELY(status == MS_FAILURE)) { msFreeImage(tileimg); return NULL; } tile = addTileCache(img,tileimg,symbol,s,width,height); } return tile->image; }
int agg2RenderGlyphsLine(imageObj *img, labelPathObj *labelpath, labelStyleObj *style, char *text) { AGG2Renderer *r = AGG_RENDERER(img); aggRendererCache *cache = (aggRendererCache*)MS_RENDERER_CACHE(MS_IMAGE_RENDERER(img)); if(aggLoadFont(cache,style->fonts[0],style->size) == MS_FAILURE) return MS_FAILURE; r->m_rasterizer_aa.filling_rule(mapserver::fill_non_zero); const mapserver::glyph_cache* glyph; int unicode; int curfontidx = 0; font_curve_type m_curves(cache->m_fman.path_adaptor()); mapserver::path_storage glyphs; for (int i = 0; i < labelpath->path.numpoints; i++) { assert(text); mapserver::trans_affine mtx; mtx *= mapserver::trans_affine_translation(-labelpath->path.point[i].x,-labelpath->path.point[i].y); mtx *= mapserver::trans_affine_rotation(-labelpath->angles[i]); mtx *= mapserver::trans_affine_translation(labelpath->path.point[i].x,labelpath->path.point[i].y); text += msUTF8ToUniChar(text, &unicode); if(curfontidx != 0) { if(aggLoadFont(cache,style->fonts[0],style->size) == MS_FAILURE) return MS_FAILURE; curfontidx = 0; } glyph = cache->m_fman.glyph(unicode); if(!glyph || glyph->glyph_index == 0) { int i; for(i=1; i<style->numfonts; i++) { if(aggLoadFont(cache,style->fonts[i],style->size) == MS_FAILURE) return MS_FAILURE; curfontidx = i; glyph = cache->m_fman.glyph(unicode); if(glyph && glyph->glyph_index != 0) { break; } } } if (glyph) { cache->m_fman.init_embedded_adaptors(glyph, labelpath->path.point[i].x,labelpath->path.point[i].y); mapserver::conv_transform<font_curve_type, mapserver::trans_affine> trans_c(m_curves, mtx); glyphs.concat_path(trans_c); } } if (style->outlinewidth) { r->m_rasterizer_aa.reset(); r->m_rasterizer_aa.filling_rule(mapserver::fill_non_zero); mapserver::conv_contour<mapserver::path_storage> cc(glyphs); cc.width(style->outlinewidth + 1); r->m_rasterizer_aa.add_path(cc); r->m_renderer_scanline.color(aggColor(style->outlinecolor)); mapserver::render_scanlines(r->m_rasterizer_aa, r->sl_line, r->m_renderer_scanline); } if (style->color) { r->m_rasterizer_aa.reset(); r->m_rasterizer_aa.filling_rule(mapserver::fill_non_zero); r->m_rasterizer_aa.add_path(glyphs); r->m_renderer_scanline.color(aggColor(style->color)); mapserver::render_scanlines(r->m_rasterizer_aa, r->sl_line, r->m_renderer_scanline); } return MS_SUCCESS; }
int agg2RenderGlyphs(imageObj *img, double x, double y, labelStyleObj *style, char *text) { AGG2Renderer *r = AGG_RENDERER(img); aggRendererCache *cache = (aggRendererCache*)MS_RENDERER_CACHE(MS_IMAGE_RENDERER(img)); if(aggLoadFont(cache,style->fonts[0],style->size) == MS_FAILURE) return MS_FAILURE; r->m_rasterizer_aa.filling_rule(mapserver::fill_non_zero); int curfontidx = 0; const mapserver::glyph_cache* glyph; int unicode; font_curve_type m_curves(cache->m_fman.path_adaptor()); mapserver::trans_affine mtx; mtx *= mapserver::trans_affine_translation(-x, -y); /*agg angles are antitrigonometric*/ mtx *= mapserver::trans_affine_rotation(-style->rotation); mtx *= mapserver::trans_affine_translation(x, y); double fx = x, fy = y; const char *utfptr = text; mapserver::path_storage glyphs; //first render all the glyphs to a path while (*utfptr) { if (*utfptr == '\r') { fx = x; utfptr++; continue; } if (*utfptr == '\n') { fx = x; fy += ceil(style->size * AGG_LINESPACE); utfptr++; continue; } utfptr += msUTF8ToUniChar(utfptr, &unicode); if(curfontidx != 0) { if(aggLoadFont(cache,style->fonts[0],style->size) == MS_FAILURE) return MS_FAILURE; curfontidx = 0; } glyph = cache->m_fman.glyph(unicode); if(!glyph || glyph->glyph_index == 0) { int i; for(i=1; i<style->numfonts; i++) { if(aggLoadFont(cache,style->fonts[i],style->size) == MS_FAILURE) return MS_FAILURE; curfontidx = i; glyph = cache->m_fman.glyph(unicode); if(glyph && glyph->glyph_index != 0) { break; } } } if (glyph) { //cache->m_fman.add_kerning(&fx, &fy); cache->m_fman.init_embedded_adaptors(glyph, fx, fy); mapserver::conv_transform<font_curve_type, mapserver::trans_affine> trans_c(m_curves, mtx); glyphs.concat_path(trans_c); fx += glyph->advance_x; fy += glyph->advance_y; } } if (style->outlinewidth) { r->m_rasterizer_aa.reset(); r->m_rasterizer_aa.filling_rule(mapserver::fill_non_zero); mapserver::conv_contour<mapserver::path_storage> cc(glyphs); cc.width(style->outlinewidth + 1); r->m_rasterizer_aa.add_path(cc); r->m_renderer_scanline.color(aggColor(style->outlinecolor)); mapserver::render_scanlines(r->m_rasterizer_aa, r->sl_line, r->m_renderer_scanline); } if (style->color) { r->m_rasterizer_aa.reset(); r->m_rasterizer_aa.filling_rule(mapserver::fill_non_zero); r->m_rasterizer_aa.add_path(glyphs); r->m_renderer_scanline.color(aggColor(style->color)); mapserver::render_scanlines(r->m_rasterizer_aa, r->sl_line, r->m_renderer_scanline); } return MS_SUCCESS; }
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 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); }
/* {{{ proto void pasteImage(imageObj Src, int transparentColor [[,int dstx, int dsty], int angle]) Pastes another imageObj on top of this imageObj. transparentColor is the color (0xrrggbb) from srcImg that should be considered transparent. Pass transparentColor=-1 if you don't want any transparent color. If optional dstx,dsty are provided then they define the position where the image should be copied (dstx,dsty = top-left corner position). The optional angle is a value between 0 and 360 degrees to rotate the source image counterclockwise. Note that if a rotation is requested then the dstx and dsty coordinates specify the CENTER of the destination area. NOTE : this function only works for 8 bits GD images. */ PHP_METHOD(imageObj, pasteImage) { long transparent=-1, dstx=0, dsty=0, angle=0; int angleSet=MS_FALSE; zval *zimage; zval *zobj = getThis(); php_image_object *php_image, *php_imageSrc; /*int oldTransparentColor, newTransparentColor=-1, r, g, b;*/ rendererVTableObj *renderer = NULL; rasterBufferObj rb; PHP_MAPSCRIPT_ERROR_HANDLING(TRUE); if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ol|lll", &zimage, mapscript_ce_image, &transparent, &dstx, &dsty, &angle) == FAILURE) { PHP_MAPSCRIPT_RESTORE_ERRORS(TRUE); return; } PHP_MAPSCRIPT_RESTORE_ERRORS(TRUE); if (ZEND_NUM_ARGS() == 3) { mapscript_report_php_error(E_WARNING, "dstX parameter given but not dstY" TSRMLS_CC); } else angleSet = MS_TRUE; php_image = (php_image_object *) zend_object_store_get_object(zobj TSRMLS_CC); php_imageSrc = (php_image_object *) zend_object_store_get_object(zimage TSRMLS_CC); if (!MS_RENDERER_PLUGIN(php_imageSrc->image->format) || !MS_RENDERER_PLUGIN(php_image->image->format)) { mapscript_throw_exception("PasteImage function should only be used with renderer plugin drivers." TSRMLS_CC); return; } #ifdef undef //USE_AGG if( MS_RENDERER_AGG(php_imageSrc->image->format)) msAlphaAGG2GD(php_imageSrc->image); if( MS_RENDERER_AGG(php_image->image->format)) msAlphaAGG2GD(php_image->image); #endif renderer = MS_IMAGE_RENDERER(php_image->image); memset(&rb,0,sizeof(rasterBufferObj)); renderer->getRasterBufferHandle(php_imageSrc->image, &rb); renderer->mergeRasterBuffer(php_image->image, &rb, 1.0, 0, 0, dstx, dsty, rb.width, rb.height); /* Look for r,g,b in color table and make it transparent. * will return -1 if there is no exact match which will result in * no transparent color in the call to gdImageColorTransparent(). */ /* if (transparent != -1) { r = (transparent / 0x010000) & 0xff; g = (transparent / 0x0100) & 0xff; b = transparent & 0xff; newTransparentColor = gdImageColorExact(php_imageSrc->image->img.gd, r, g, b); } oldTransparentColor = gdImageGetTransparent(php_imageSrc->image->img.gd); gdImageColorTransparent(php_imageSrc->image->img.gd, newTransparentColor); if (!angleSet) gdImageCopy(php_image->image->img.gd, php_imageSrc->image->img.gd, dstx, dsty, 0, 0, php_imageSrc->image->img.gd->sx, php_imageSrc->image->img.gd->sy); else gdImageCopyRotated(php_image->image->img.gd, php_imageSrc->image->img.gd, dstx, dsty, 0, 0, php_imageSrc->image->img.gd->sx, php_imageSrc->image->img.gd->sy, angle); gdImageColorTransparent(php_imageSrc->image->img.gd, oldTransparentColor);*/ RETURN_LONG(MS_SUCCESS); }