/* * 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 msUVRASTERLayerWhichShapes(layerObj *layer, rectObj rect, int isQuery) { uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *) layer->layerinfo; imageObj *image_tmp; outputFormatObj *outputformat = NULL; mapObj *map_tmp; double map_cellsize; unsigned int spacing; int width, height, u_src_off, v_src_off, i, x, y; char **alteredProcessing = NULL, *saved_layer_mask; char **savedProcessing = NULL; if (layer->debug) msDebug("Entering msUVRASTERLayerWhichShapes().\n"); if( uvlinfo == NULL ) return MS_FAILURE; /* QUERY NOT SUPPORTED YET */ if (isQuery == MS_TRUE) { msSetError( MS_MISCERR, "Query is not supported for UV layer.", "msUVRASTERLayerWhichShapes()" ); return MS_FAILURE; } if( CSLFetchNameValue( layer->processing, "BANDS" ) == NULL ) { msSetError( MS_MISCERR, "BANDS processing option is required for UV layer. You have to specified 2 bands.", "msUVRASTERLayerWhichShapes()" ); return MS_FAILURE; } /* ** Allocate mapObj structure */ map_tmp = (mapObj *)msSmallCalloc(sizeof(mapObj),1); if(initMap(map_tmp) == -1) { /* initialize this map */ msFree(map_tmp); return(MS_FAILURE); } /* -------------------------------------------------------------------- */ /* Determine desired spacing. Default to 32 if not otherwise set */ /* -------------------------------------------------------------------- */ spacing = 32; if( CSLFetchNameValue( layer->processing, "UV_SPACING" ) != NULL ) { spacing = atoi(CSLFetchNameValue( layer->processing, "UV_SPACING" )); } width = (int)ceil(layer->map->width/spacing); height = (int)ceil(layer->map->height/spacing); map_cellsize = MS_MAX(MS_CELLSIZE(rect.minx, rect.maxx,layer->map->width), MS_CELLSIZE(rect.miny,rect.maxy,layer->map->height)); map_tmp->cellsize = map_cellsize*spacing; if (layer->debug) msDebug("msUVRASTERLayerWhichShapes(): width: %d, height: %d, cellsize: %g\n", width, height, map_tmp->cellsize); /* Initialize our dummy map */ MS_INIT_COLOR(map_tmp->imagecolor, 255,255,255,255); map_tmp->resolution = layer->map->resolution; map_tmp->defresolution = layer->map->defresolution; outputformat = (outputFormatObj *) msSmallCalloc(1,sizeof(outputFormatObj)); outputformat->bands = uvlinfo->band_count = 2; outputformat->name = NULL; outputformat->driver = NULL; outputformat->refcount = 0; outputformat->vtable = NULL; outputformat->device = NULL; outputformat->renderer = MS_RENDER_WITH_RAWDATA; outputformat->imagemode = MS_IMAGEMODE_FLOAT32; msAppendOutputFormat(map_tmp, outputformat); msCopyHashTable(&map_tmp->configoptions, &layer->map->configoptions); map_tmp->mappath = msStrdup(layer->map->mappath); map_tmp->shapepath = msStrdup(layer->map->shapepath); map_tmp->extent.minx = rect.minx-(0.5*map_cellsize)+(0.5*map_tmp->cellsize); map_tmp->extent.miny = rect.miny-(0.5*map_cellsize)+(0.5*map_tmp->cellsize); map_tmp->extent.maxx = map_tmp->extent.minx+((width-1)*map_tmp->cellsize); map_tmp->extent.maxy = map_tmp->extent.miny+((height-1)*map_tmp->cellsize); map_tmp->gt.rotation_angle = 0.0; msCopyProjection(&map_tmp->projection, &layer->projection); if (layer->debug == 5) msDebug("msUVRASTERLayerWhichShapes(): extent: %g %g %g %g\n", map_tmp->extent.minx, map_tmp->extent.miny, map_tmp->extent.maxx, map_tmp->extent.maxy); /* important to use that function, to compute map geotransform, used by the resampling*/ msMapSetSize(map_tmp, width, height); if (layer->debug == 5) msDebug("msUVRASTERLayerWhichShapes(): geotransform: %g %g %g %g %g %g\n", map_tmp->gt.geotransform[0], map_tmp->gt.geotransform[1], map_tmp->gt.geotransform[2], map_tmp->gt.geotransform[3], map_tmp->gt.geotransform[4], map_tmp->gt.geotransform[5]); uvlinfo->extent = map_tmp->extent; image_tmp = msImageCreate(width, height, map_tmp->outputformatlist[0], NULL, NULL, map_tmp->resolution, map_tmp->defresolution, &(map_tmp->imagecolor)); /* Default set to AVERAGE resampling */ if( CSLFetchNameValue( layer->processing, "RESAMPLE" ) == NULL ) { alteredProcessing = CSLDuplicate( layer->processing ); alteredProcessing = CSLSetNameValue( alteredProcessing, "RESAMPLE", "AVERAGE"); savedProcessing = layer->processing; layer->processing = alteredProcessing; } /* disable masking at this level: we don't want to apply the mask at the raster level, * it will be applied with the correct cellsize and image size in the vector rendering * phase. */ saved_layer_mask = layer->mask; layer->mask = NULL; if (msDrawRasterLayerLow(map_tmp, layer, image_tmp, NULL ) == MS_FAILURE) { msSetError(MS_MISCERR, "Unable to draw raster data.", "msUVRASTERLayerWhichShapes()"); layer->mask = saved_layer_mask; return MS_FAILURE; } /* restore layer mask */ layer->mask = saved_layer_mask; /* restore the saved processing */ if (alteredProcessing != NULL) { layer->processing = savedProcessing; CSLDestroy(alteredProcessing); } /* free old query arrays */ if (uvlinfo->u) { for (i=0; i<uvlinfo->width; ++i) { free(uvlinfo->u[i]); } free(uvlinfo->u); } if (uvlinfo->v) { for (i=0; i<uvlinfo->height; ++i) { free(uvlinfo->v[i]); } free(uvlinfo->v); } /* Update our uv layer structure */ uvlinfo->width = width; uvlinfo->height = height; uvlinfo->query_results = width*height; uvlinfo->u = (float **)msSmallMalloc(sizeof(float *)*width); uvlinfo->v = (float **)msSmallMalloc(sizeof(float *)*width); for (x = 0; x < width; ++x) { uvlinfo->u[x] = (float *)msSmallMalloc(height * sizeof(float)); uvlinfo->v[x] = (float *)msSmallMalloc(height * sizeof(float)); for (y = 0; y < height; ++y) { u_src_off = v_src_off = x + y * width; v_src_off += width*height; uvlinfo->u[x][y] = image_tmp->img.raw_float[u_src_off]; uvlinfo->v[x][y] = image_tmp->img.raw_float[v_src_off]; /* null vector? update the number of results */ if (uvlinfo->u[x][y] == 0 && uvlinfo->v[x][y] == 0) --uvlinfo->query_results; } } msFreeImage(image_tmp); /* we do not need the imageObj anymore */ msFreeMap(map_tmp); uvlinfo->next_shape = 0; return MS_SUCCESS; }
/* 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); }
/* * 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; }
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); }
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; }
/************************************************************************ * msTileExtractSubTile * * * ************************************************************************/ static imageObj* msTileExtractSubTile(const mapservObj *msObj, const imageObj *img) { int width, height, mini, minj, maxi, maxj; int zoom = 2; imageObj* imgOut = NULL; tileParams params; rendererVTableObj *renderer; rasterBufferObj imgBuffer; if( !MS_RENDERER_PLUGIN(msObj->map->outputformat) || msObj->map->outputformat->renderer != img->format->renderer || ! MS_MAP_RENDERER(msObj->map)->supports_pixel_buffer ) { msSetError(MS_MISCERR,"unsupported or mixed renderers","msTileExtractSubTile()"); return NULL; } renderer = MS_MAP_RENDERER(msObj->map); if (renderer->getRasterBufferHandle((imageObj*)img,&imgBuffer) != MS_SUCCESS) { return NULL; } /* ** Load the metatiling information from the map file. */ msTileGetParams(msObj->map, ¶ms); /* ** Initialize values for the metatile clip area. */ width = img->width - 2*params.map_edge_buffer; height = img->height - 2*params.map_edge_buffer; mini = params.map_edge_buffer; minj = params.map_edge_buffer; maxi = img->width - params.map_edge_buffer - 1; maxj = img->height - params.map_edge_buffer - 1; if( msObj->TileMode == TILE_GMAP ) { int x, y, zoom; if( msObj->TileCoords ) { if( msTileGetGMapCoords(msObj->TileCoords, &x, &y, &zoom) == MS_FAILURE ) return NULL; } else { msSetError(MS_WEBERR, "Tile parameter not set.", "msTileSetup()"); return NULL; } if(msObj->map->debug) msDebug("msTileExtractSubTile(): gmaps coords (x: %d, y: %d)\n",x,y); /* ** The bottom N bits of the coordinates give us the subtile ** location relative to the metatile. */ x = (0xffff ^ (0xffff << params.metatile_level)) & x; y = (0xffff ^ (0xffff << params.metatile_level)) & y; if(msObj->map->debug) msDebug("msTileExtractSubTile(): gmaps image coords (x: %d, y: %d)\n",x,y); mini = mini + x * params.tile_size; minj = minj + y * params.tile_size; } else if( msObj->TileMode == TILE_VE ) { int tsize; int i = 0; char j = 0; if( strlen( msObj->TileCoords ) - params.metatile_level < 0 ) { return(NULL); } /* ** Process the last elements of the VE coordinate string to place the ** requested tile in the context of the metatile */ for( i = strlen( msObj->TileCoords ) - params.metatile_level; i < strlen( msObj->TileCoords ); i++ ) { j = msObj->TileCoords[i]; tsize = width / zoom; if( j == '1' || j == '3' ) mini += tsize; if( j == '2' || j == '3' ) minj += tsize; zoom *= 2; } } else { return(NULL); /* Huh? Should have a mode. */ } imgOut = msImageCreate(params.tile_size, params.tile_size, msObj->map->outputformat, NULL, NULL, msObj->map->resolution, msObj->map->defresolution, NULL); if( imgOut == NULL ) { return NULL; } if(msObj->map->debug) msDebug("msTileExtractSubTile(): extracting (%d x %d) tile, top corner (%d, %d)\n",params.tile_size,params.tile_size,mini,minj); renderer->mergeRasterBuffer(imgOut,&imgBuffer,1.0,mini, minj,0, 0,params.tile_size, params.tile_size); return imgOut; }