int agg2RenderBitmapGlyphs(imageObj *img, double x, double y, labelStyleObj *style, char *text) { typedef mapserver::glyph_raster_bin<color_type> glyph_gen; int size = MS_NINT(style->size); if(size<0 || size>4) { msSetError(MS_RENDERERERR,"invalid bitmap font size", "agg2RenderBitmapGlyphs()"); return MS_FAILURE; } AGG2Renderer *r = AGG_RENDERER(img); glyph_gen glyph(0); mapserver::renderer_raster_htext_solid<renderer_base, glyph_gen> rt(r->m_renderer_base, glyph); glyph.font(rasterfonts[size]); int numlines=0; char **lines; /*masking out the out-of-range character codes*/ int len; int cc_start = rasterfonts[size][2]; int cc_end = cc_start + rasterfonts[size][3]; if(msCountChars(text,'\n')) { if((lines = msStringSplit((const char*)text, '\n', &(numlines))) == NULL) return(-1); } else { lines = &text; numlines = 1; } y -= glyph.base_line(); for(int n=0; n<numlines; n++) { len = strlen(lines[n]); for (int i = 0; i < len; i++) if (lines[n][i] < cc_start || lines[n][i] > cc_end) lines[n][i] = '.'; if(style->outlinewidth > 0) { rt.color(aggColor(style->outlinecolor)); for(int i=-1; i<=1; i++) { for(int j=-1; j<=1; j++) { if(i||j) { rt.render_text(x+i, y+j, lines[n], true); } } } } assert(style->color); rt.color(aggColor(style->color)); rt.render_text(x, y, lines[n], true); y += glyph.height(); } if(*lines != text) msFreeCharArray(lines, numlines); return MS_SUCCESS; return MS_SUCCESS; }
int renderBitmapGlyphsGD(imageObj *img, double x, double y, labelStyleObj *style, char *text) { int size = MS_NINT(style->size); gdFontPtr fontPtr; gdImagePtr ip; int numlines=0,t; char **lines; if(!(ip = MS_IMAGE_GET_GDIMAGEPTR(img))) return MS_FAILURE; if(size<0 || size>4 || (fontPtr = msGetBitmapFont(size))==NULL) { msSetError(MS_RENDERERERR,"invalid bitmap font size", "renderBitmapGlyphsGD()"); return MS_FAILURE; } SETPEN(ip, style->color); SETPEN(ip, style->outlinecolor); if(msCountChars(text,'\n')) { if((lines = msStringSplit((const char*)text, '\n', &(numlines))) == NULL) return(-1); } else { lines = &text; numlines = 1; } y -= fontPtr->h; for(t=0; t<numlines; t++) { if(style->outlinewidth > 0) { gdImageString(ip, fontPtr, x, y-1, (unsigned char *) lines[t], style->outlinecolor->pen); gdImageString(ip, fontPtr, x, y+1, (unsigned char *) lines[t], style->outlinecolor->pen); gdImageString(ip, fontPtr, x+1, y, (unsigned char *) lines[t], style->outlinecolor->pen); gdImageString(ip, fontPtr, x-1, y, (unsigned char *) lines[t], style->outlinecolor->pen); gdImageString(ip, fontPtr, x+1, y-1, (unsigned char *) lines[t], style->outlinecolor->pen); gdImageString(ip, fontPtr, x+1, y+1, (unsigned char *) lines[t], style->outlinecolor->pen); gdImageString(ip, fontPtr, x-1, y-1, (unsigned char *) lines[t], style->outlinecolor->pen); gdImageString(ip, fontPtr, x-1, y+1, (unsigned char *) lines[t], style->outlinecolor->pen); } if(style->color->pen != -1) { gdImageString(ip, fontPtr, x, y, (unsigned char *) lines[t], style->color->pen); } y += fontPtr->h; /* shift down */ } if(lines != &text) msFreeCharArray(lines, numlines); return MS_SUCCESS; }
/** * replace wrap characters with \n , respecting maximal line length. * * returns a pointer to the newly allocated text. memory is controlled * inside this function, so the caller MUST use the pointer returned by * the function: * text = msWrapText(label,text); * * TODO/FIXME: function will produce erroneous/crashing? results * if the wrap character is encoded with multiple bytes * * see http://mapserver.org/development/rfc/ms-rfc-40.html * for a summary of how wrap/maxlength interact on the result * of the text transformation */ char *msWrapText(labelObj *label, char *text) { char wrap; int maxlength; if(!text) /*not an error if no text*/ return text; wrap = label->wrap; maxlength = label->maxlength; if(maxlength == 0) { if(wrap!='\0') { /* if maxlength = 0 *and* a wrap character was specified, * replace all wrap characters by \n * this is the traditional meaning of the wrap character */ msReplaceChar(text, wrap, '\n'); } /* if neither maxlength, nor wrap were specified, * don't transform this text */ return text; } else if(maxlength>0) { if(wrap!='\0') { /* split input text at the wrap character, only if * the current line length is over maxlength */ /* TODO: check if the wrap character is a valid byte * inside a multibyte utf8 glyph. if so, the msCountChars * will return an erroneous value */ int numwrapchars = msCountChars(text,wrap); if(numwrapchars > 0) { if(label->encoding) { /* we have to use utf decoding functions here, so as not to * split a text line on a multibyte character */ int num_cur_glyph_on_line = 0; /*count for the number of glyphs on the current line*/ char *textptr = text; char glyph[11]; /*storage for unicode fetching function*/ int glyphlen = 0; /*size of current glyph in bytes*/ while((glyphlen = msGetNextGlyph((const char**)&textptr,glyph))>0) { num_cur_glyph_on_line++; if(*glyph == wrap && num_cur_glyph_on_line>=(maxlength)) { /*FIXME (if wrap becomes something other than char):*/ *(textptr-1)='\n'; /*replace wrap char with a \n*/ num_cur_glyph_on_line=0; /*reset count*/ } } } else { int cur_char_on_line = 0; char *textptr = text; while(*textptr != 0) { cur_char_on_line++; if(*textptr == wrap && cur_char_on_line>=maxlength) { *textptr='\n'; /*replace wrap char with a \n*/ cur_char_on_line=0; /*reset count*/ } textptr++; } } return text; } else { /*there are no characters available for wrapping*/ return text; } } else { /* if no wrap character was specified, but a maxlength was, * don't draw this label if it is longer than the specified maxlength*/ if(msGetNumGlyphs(text)>maxlength) { free(text); return NULL; } else { return text; } } } else { /* negative maxlength: we split lines unconditionally, i.e. without loooking for a wrap character*/ int numglyphs,numlines; maxlength = -maxlength; /* use a positive value*/ numglyphs = msGetNumGlyphs(text); numlines = (numglyphs-1) / maxlength + 1; /*count total number of lines needed after splitting*/ if(numlines>1) { char *newtext = msSmallMalloc(strlen(text)+numlines+1); char *newtextptr = newtext; char *textptr = text; int glyphlen = 0, num_cur_glyph = 0; while((glyphlen = msGetNextGlyph((const char**)&textptr,newtextptr))>0) { num_cur_glyph++; newtextptr += glyphlen; if(num_cur_glyph%maxlength == 0 && num_cur_glyph != numglyphs) { /*we're at a split location, insert a newline*/ *newtextptr = '\n'; newtextptr++; } } free(text); return newtext; } else { /*no splitting needed, return the original*/ return text; } } }
char *msAlignText(mapObj *map, labelObj *label, char *text) { double spacewidth=0.0; /*size of a single space, in fractional pixels*/ int numlines; char **textlines,*newtext,*newtextptr; int *textlinelengths,*numspacesforpadding; int numspacestoadd,maxlinelength,i; rectObj label_rect; if(!msCountChars(text,'\n')) return text; /*only one line*/ /*split text into individual lines * TODO: check if splitting on \n is utf8 safe*/ textlines = msStringSplit(text,'\n',&numlines); /* * label->space_size_10 contains a cache for the horizontal size of a single * 'space' character, at size 10 for the current label * FIXME: in case of attribute binding for the FONT of the label, this cache will * be wrong for labels where the attributed font is different than the first * computed font. This shouldn't happen too often, and hopefully the size of a * space character shouldn't vary too much between different fonts*/ if(label->space_size_10 == 0.0) { /*if the cache hasn't been initialized yet, or with pixmap fonts*/ /* compute the size of 16 adjacent spaces. we can't do this for just one space, * as the labelSize computing functions return integer bounding boxes. we assume * that the integer rounding for such a number of spaces will be negligeable * compared to the actual size of thoses spaces */ if(msGetLabelSize(map,label,". .",10.0,&label_rect,NULL) != MS_SUCCESS) { /*error computing label size, we can't continue*/ /*free the previously allocated split text*/ while(numlines--) free(textlines[numlines]); free(textlines); return text; } /* this is the size of a single space character. for truetype fonts, * it's the size of a 10pt space. For pixmap fonts, it's the size * for the current label */ spacewidth = (label_rect.maxx-label_rect.minx)/16.0; if(label->type == MS_TRUETYPE) { label->space_size_10=spacewidth; /*cache the computed size*/ /*size of a space for current label size*/ spacewidth = spacewidth * (double)label->size/10.0; } } else { spacewidth = label->space_size_10 * (double)label->size/10.0; } spacewidth = MS_MAX(1,spacewidth); /*length in pixels of each line*/ textlinelengths = (int*)msSmallMalloc(numlines*sizeof(int)); /*number of spaces that need to be added to each line*/ numspacesforpadding = (int*)msSmallMalloc(numlines*sizeof(int)); /*total number of spaces that need to be added*/ numspacestoadd=0; /*length in pixels of the longest line*/ maxlinelength=0; for(i=0; i<numlines; i++) { if(MS_SUCCESS != msGetLabelSize(map,label,textlines[i],label->size, &label_rect,NULL)) { msFreeCharArray(textlines,numlines); msFree(textlinelengths); msFree(numspacesforpadding); return text; } textlinelengths[i] = label_rect.maxx-label_rect.minx; if(maxlinelength<textlinelengths[i]) maxlinelength=textlinelengths[i]; } for(i=0; i<numlines; i++) { /* number of spaces to add so the current line is * as long as the longest line */ double nfracspaces = (maxlinelength - textlinelengths[i])/spacewidth; if(label->align == MS_ALIGN_CENTER) { numspacesforpadding[i]=MS_NINT(nfracspaces/2.0); } else { if(label->align == MS_ALIGN_RIGHT) { numspacesforpadding[i]=MS_NINT(nfracspaces); } } numspacestoadd+=numspacesforpadding[i]; } /*allocate new text with room for the additional spaces needed*/ newtext = (char*)msSmallMalloc(strlen(text)+1+numspacestoadd); newtextptr=newtext; for(i=0; i<numlines; i++) { int j; /*padd beginning of line with needed spaces*/ for(j=0; j<numspacesforpadding[i]; j++) { *(newtextptr++)=' '; } /*copy original line*/ strcpy(newtextptr,textlines[i]); /*place pointer at the char right after the current line*/ newtextptr+=strlen(textlines[i])+1; if(i!=numlines-1) { /*put the \n back in (was taken away by msStringSplit)*/ *(newtextptr-1)='\n'; } } /*free the original text*/ free(text); for(i=0; i<numlines; i++) { free(textlines[i]); } free(textlines); free(textlinelengths); free(numspacesforpadding); /*return the aligned text. note that the terminating \0 was added by the last * call to strcpy */ return newtext; }