1 /* Copyright (C) 2000-2012 by George Williams */
2 /*
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are met:
5
6 * Redistributions of source code must retain the above copyright notice, this
7 * list of conditions and the following disclaimer.
8
9 * Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12
13 * The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include <fontforge-config.h>
29
30 #include "cvimages.h"
31
32 #include "cvundoes.h"
33 #include "fontforgevw.h"
34 #include "fvfonts.h"
35 #include "parsepdf.h"
36 #include "psread.h"
37 #include "sd.h"
38 #include "spiro.h"
39 #include "splinefit.h"
40 #include "splineorder2.h"
41 #include "splineutil.h"
42 #include "splineutil2.h"
43 #include "svg.h"
44 #include "ustring.h"
45 #include "utype.h"
46
47 #include <assert.h>
48 #include <dirent.h>
49 #include <math.h>
50 #include <sys/types.h>
51
InitImportParams(ImportParams * ip)52 void InitImportParams(ImportParams *ip) {
53 assert( ip!=NULL );
54
55 memset(ip, 0, sizeof(ImportParams));
56
57 ip->initialized = true;
58
59 ip->correct_direction = true;
60 ip->simplify = true;
61 ip->clip = true;
62 ip->scale = true;
63 ip->accuracy_target = 0.25;
64 ip->default_joinlimit = JLIMIT_INHERITED;
65 }
66
ImportParamsState()67 ImportParams *ImportParamsState() {
68 static ImportParams ips;
69
70 if ( !ips.initialized )
71 InitImportParams(&ips);
72
73 return &ips;
74 }
75
SCAppendEntityLayers(SplineChar * sc,Entity * ent,ImportParams * ip)76 void SCAppendEntityLayers(SplineChar *sc, Entity *ent, ImportParams *ip) {
77 int cnt, pos;
78 Entity *e, *enext;
79 Layer *old = sc->layers;
80 SplineSet *ss;
81
82 for ( e=ent, cnt=0; e!=NULL; e=e->next, ++cnt );
83 pos = sc->layer_cnt;
84 if ( cnt==0 )
85 return;
86 EntityDefaultStrokeFill(ent);
87
88 sc->layers = realloc(sc->layers,(sc->layer_cnt+cnt)*sizeof(Layer));
89 for ( pos = sc->layer_cnt, e=ent; e!=NULL ; e=enext, ++pos ) {
90 enext = e->next;
91 LayerDefault(&sc->layers[pos]);
92 sc->layers[pos].splines = NULL;
93 sc->layers[pos].refs = NULL;
94 sc->layers[pos].images = NULL;
95 if ( e->type == et_splines ) {
96 sc->layers[pos].dofill = e->u.splines.fill.col != 0xffffffff;
97 sc->layers[pos].dostroke = e->u.splines.stroke.col != 0xffffffff;
98 if ( !sc->layers[pos].dofill && !sc->layers[pos].dostroke )
99 sc->layers[pos].dofill = true; /* If unspecified, assume an implied fill in BuildGlyph */
100 sc->layers[pos].fill_brush.col = e->u.splines.fill.col==0xffffffff ?
101 COLOR_INHERITED : e->u.splines.fill.col;
102 sc->layers[pos].fill_brush.gradient = e->u.splines.fill.grad;
103 /*!!!!!! pattern? */
104 sc->layers[pos].stroke_pen.brush.col = e->u.splines.stroke.col==0xffffffff ? COLOR_INHERITED : e->u.splines.stroke.col;
105 sc->layers[pos].stroke_pen.brush.gradient = e->u.splines.stroke.grad;
106 sc->layers[pos].stroke_pen.width = e->u.splines.stroke_width;
107 sc->layers[pos].stroke_pen.linejoin = e->u.splines.join;
108 sc->layers[pos].stroke_pen.linecap = e->u.splines.cap;
109 memcpy(sc->layers[pos].stroke_pen.trans, e->u.splines.transform,
110 4*sizeof(real));
111 sc->layers[pos].splines = e->u.splines.splines;
112 } else if ( e->type == et_image ) {
113 ImageList *ilist = chunkalloc(sizeof(ImageList));
114 struct _GImage *base = e->u.image.image->list_len==0?
115 e->u.image.image->u.image:e->u.image.image->u.images[0];
116 sc->layers[pos].images = ilist;
117 sc->layers[pos].dofill = base->image_type==it_mono && base->trans!=(Color)-1;
118 sc->layers[pos].fill_brush.col = e->u.image.col==0xffffffff ?
119 COLOR_INHERITED : e->u.image.col;
120 ilist->image = e->u.image.image;
121 ilist->xscale = e->u.image.transform[0];
122 ilist->yscale = e->u.image.transform[3];
123 ilist->xoff = e->u.image.transform[4];
124 ilist->yoff = e->u.image.transform[5];
125 ilist->bb.minx = ilist->xoff;
126 ilist->bb.maxy = ilist->yoff;
127 ilist->bb.maxx = ilist->xoff + base->width*ilist->xscale;
128 ilist->bb.miny = ilist->yoff - base->height*ilist->yscale;
129 }
130 if ( e->clippath ) {
131 for ( ss=e->clippath; ss->next!=NULL; ss=ss->next )
132 ss->is_clip_path = true;
133 ss->is_clip_path = true;
134 ss->next = sc->layers[pos].splines;
135 sc->layers[pos].splines = e->clippath;
136 }
137 free(e);
138 }
139 sc->layer_cnt += cnt;
140 SCMoreLayers(sc,old);
141 }
142
SCImportPSFile(SplineChar * sc,int layer,FILE * ps,bool doclear,ImportParams * ip)143 void SCImportPSFile(SplineChar *sc,int layer,FILE *ps,bool doclear,
144 ImportParams *ip) {
145 SplinePointList *spl, *espl;
146 SplineSet **head;
147 int empty, width;
148
149 if ( ps==NULL )
150 return;
151 width = UNDEFINED_WIDTH;
152 empty = sc->layers[layer].splines==NULL && sc->layers[layer].refs==NULL;
153 if ( sc->parent->multilayer && layer>ly_back ) {
154 SCAppendEntityLayers(sc, EntityInterpretPS(ps,&width), ip);
155 } else {
156 spl = SplinePointListInterpretPS(ps,ip,sc->parent->strokedfont,&width);
157 if ( spl==NULL ) {
158 ff_post_error( _("Too Complex or Bad"), _("I'm sorry this file is too complex for me to understand (or is erroneous, or is empty)") );
159 return;
160 }
161 if ( sc->layers[layer].order2 )
162 spl = SplineSetsConvertOrder(spl,true);
163 for ( espl=spl; espl->next!=NULL; espl = espl->next );
164 if ( layer==ly_grid )
165 head = &sc->parent->grid.splines;
166 else {
167 SCPreserveLayer(sc,layer,false);
168 head = &sc->layers[layer].splines;
169 }
170 if ( doclear ) {
171 SplinePointListsFree(*head);
172 *head = NULL;
173 }
174 espl->next = *head;
175 *head = spl;
176 }
177 if ( (empty || doclear) && width!=UNDEFINED_WIDTH )
178 SCSynchronizeWidth(sc,width,sc->width,NULL);
179 SCCharChangedUpdate(sc,layer);
180 }
181
SCImportPS(SplineChar * sc,int layer,char * path,bool doclear,ImportParams * ip)182 void SCImportPS(SplineChar *sc,int layer,char *path,bool doclear,
183 ImportParams *ip) {
184 FILE *ps = fopen(path,"r");
185
186 if ( ps==NULL )
187 return;
188 SCImportPSFile(sc,layer,ps,doclear,ip);
189 fclose(ps);
190 }
191
SCImportPDFFile(SplineChar * sc,int layer,FILE * pdf,bool doclear,ImportParams * ip)192 void SCImportPDFFile(SplineChar *sc,int layer,FILE *pdf,bool doclear,
193 ImportParams *ip) {
194 SplinePointList *spl, *espl;
195 SplineSet **head;
196 bigreal tmpjl = ip->default_joinlimit;
197
198 if ( pdf==NULL )
199 return;
200
201 if ( sc->parent->multilayer && layer>ly_back ) {
202 SCAppendEntityLayers(sc, EntityInterpretPDFPage(pdf,-1), ip);
203 } else {
204 if ( tmpjl==JLIMIT_INHERITED )
205 ip->default_joinlimit = 10.0; // PostScript default
206 spl = SplinesFromEntities(EntityInterpretPDFPage(pdf,-1),ip,sc->parent->strokedfont);
207 ip->default_joinlimit = tmpjl;
208 if ( spl==NULL ) {
209 ff_post_error( _("Too Complex or Bad"), _("I'm sorry this file is too complex for me to understand (or is erroneous, or is empty)") );
210 return;
211 }
212 if ( sc->layers[layer].order2 )
213 spl = SplineSetsConvertOrder(spl,true);
214 for ( espl=spl; espl->next!=NULL; espl = espl->next );
215 if ( layer==ly_grid )
216 head = &sc->parent->grid.splines;
217 else {
218 SCPreserveLayer(sc,layer,false);
219 head = &sc->layers[layer].splines;
220 }
221 if ( doclear ) {
222 SplinePointListsFree(*head);
223 *head = NULL;
224 }
225 espl->next = *head;
226 *head = spl;
227 }
228 SCCharChangedUpdate(sc,layer);
229 }
230
SCImportPDF(SplineChar * sc,int layer,char * path,bool doclear,ImportParams * ip)231 void SCImportPDF(SplineChar *sc,int layer,char *path,bool doclear,
232 ImportParams *ip) {
233 FILE *pdf = fopen(path,"r");
234
235 if ( pdf==NULL )
236 return;
237 SCImportPDFFile(sc,layer,pdf,doclear,ip);
238 fclose(pdf);
239 }
240
SCImportPlateFile(SplineChar * sc,int layer,FILE * plate,bool doclear,ImportParams * ip)241 void SCImportPlateFile(SplineChar *sc,int layer,FILE *plate,bool doclear,
242 ImportParams *ip) {
243 SplineSet **ly_head, *head, *cur, *last;
244 spiro_cp *spiros=NULL;
245 int cnt=0, max=0, ch;
246 char buffer[80];
247 real transform[6];
248
249 if ( plate==NULL )
250 return;
251
252 head = last = NULL;
253 fgets(buffer,sizeof(buffer),plate);
254 if ( strncmp(buffer,"(plate",strlen("plate("))!=0 ) {
255 ff_post_error( _("Not a plate file"), _("This does not seem to be a plate file\nFirst line wrong"));
256 return;
257 }
258 while ( !feof(plate)) {
259 while ( isspace( (ch=getc(plate)) ) );
260 if ( ch==')' || ch==EOF )
261 break;
262 if ( ch!='(' ) {
263 ff_post_error( _("Not a plate file"), _("This does not seem to be a plate file\nExpected left paren"));
264 free(spiros);
265 return;
266 }
267 ch = getc(plate);
268 if ( ch!='v' && ch!='o' && ch!='c' && ch!='[' && ch!=']' && ch!='z' ) {
269 ff_post_error( _("Not a plate file"), _("This does not seem to be a plate file\nExpected one of 'voc[]z'"));
270 free(spiros);
271 return;
272 }
273 if ( cnt>=max )
274 spiros = realloc(spiros,(max+=30)*sizeof(spiro_cp));
275 spiros[cnt].x = spiros[cnt].y = 0;
276 spiros[cnt].ty = ch;
277 if ( ch=='z' ) {
278 cur = SpiroCP2SplineSet(spiros);
279 cur->spiros = SpiroCPCopy(spiros,&cur->spiro_cnt);
280 cur->spiro_max = cur->spiro_cnt;
281 SplineSetAddExtrema(sc,cur,ae_only_good,sc->parent->ascent+sc->parent->descent);
282 if ( cur==NULL )
283 /* Do Nothing */;
284 else if ( last!=NULL ) {
285 last->next = cur;
286 last = cur;
287 } else
288 head = last = cur;
289 cnt = 0;
290 ch = getc(plate); /* Must be ')' */
291 } else {
292 if ( fscanf(plate,"%lg %lg )", &spiros[cnt].x, &spiros[cnt].y)!=2 ) {
293 ff_post_error( _("Not a plate file"), _("This does not seem to be a plate file\nExpected two real numbers"));
294 free(spiros);
295 return;
296 }
297 ++cnt;
298 }
299 }
300 if ( cnt!=0 ) {
301 /* This happens when we've got an open contour */
302 if ( cnt>=max )
303 spiros = realloc(spiros,(max+=30)*sizeof(spiro_cp));
304 spiros[cnt].x = spiros[cnt].y = 0;
305 spiros[cnt].ty = 'z';
306 spiros[0].ty = '{'; /* Open contour mark */
307 cur = SpiroCP2SplineSet(spiros);
308 cur->spiros = SpiroCPCopy(spiros,&cur->spiro_cnt);
309 cur->spiro_max = cur->spiro_cnt;
310 SplineSetAddExtrema(sc,cur,ae_only_good,sc->parent->ascent+sc->parent->descent);
311 if ( cur==NULL )
312 /* Do Nothing */;
313 else if ( last!=NULL ) {
314 last->next = cur;
315 last = cur;
316 } else
317 head = last = cur;
318 }
319 free(spiros);
320
321 /* Raph's plate files seem to have the base line at 800, and glyphs grow */
322 /* downwards */ /* At least for Inconsola */
323 memset(transform,0,sizeof(transform));
324 transform[0] = 1; transform[3] = -1;
325 transform[5] = 800;
326 head = SplinePointListTransform(head,transform,tpt_AllPoints);
327 /* After doing the above flip, the contours appear oriented acording to my*/
328 /* conventions */
329
330 if ( sc->layers[layer].order2 ) {
331 head = SplineSetsConvertOrder(head,true);
332 for ( last=head; last->next!=NULL; last = last->next );
333 }
334 if ( layer==ly_grid )
335 ly_head = &sc->parent->grid.splines;
336 else {
337 SCPreserveLayer(sc,layer,false);
338 ly_head = &sc->layers[layer].splines;
339 }
340 if ( doclear ) {
341 SplinePointListsFree(*ly_head);
342 *ly_head = NULL;
343 }
344 last->next = *ly_head;
345 *ly_head = head;
346 SCCharChangedUpdate(sc,layer);
347 }
348
SCImportSVG(SplineChar * sc,int layer,char * path,char * memory,int memlen,bool doclear,ImportParams * ip)349 void SCImportSVG(SplineChar *sc,int layer,char *path,char *memory, int memlen,
350 bool doclear, ImportParams *ip) {
351 SplinePointList *spl, *espl, **head;
352
353 if ( sc->parent->multilayer && layer>ly_back ) {
354 SCAppendEntityLayers(sc,
355 EntityInterpretSVG(path,memory,memlen,
356 sc->parent->ascent+sc->parent->descent,
357 sc->parent->ascent,ip->scale), ip);
358 } else {
359 spl = SplinePointListInterpretSVG(path,memory,memlen,
360 sc->parent->ascent+sc->parent->descent,
361 sc->parent->ascent,
362 sc->parent->strokedfont, ip);
363 for ( espl = spl; espl!=NULL && espl->first->next==NULL; espl=espl->next );
364 if ( espl!=NULL )
365 if ( espl->first->next->order2!=sc->layers[layer].order2 )
366 spl = SplineSetsConvertOrder(spl,sc->layers[layer].order2);
367 if ( spl==NULL ) {
368 ff_post_error(_("Too Complex or Bad"),_("I'm sorry this file is too complex for me to understand (or is erroneous)"));
369 return;
370 }
371 for ( espl=spl; espl->next!=NULL; espl = espl->next );
372 if ( layer==ly_grid )
373 head = &sc->parent->grid.splines;
374 else {
375 SCPreserveLayer(sc,layer,false);
376 head = &sc->layers[layer].splines;
377 }
378 if ( doclear ) {
379 SplinePointListsFree(*head);
380 *head = NULL;
381 }
382 espl->next = *head;
383 *head = spl;
384 }
385 SCCharChangedUpdate(sc,layer);
386 }
387
SCImportGlif(SplineChar * sc,int layer,char * path,char * memory,int memlen,bool doclear,ImportParams * UNUSED (ip))388 void SCImportGlif(SplineChar *sc,int layer,char *path,char *memory, int memlen,
389 bool doclear, ImportParams *UNUSED(ip)) {
390 SplinePointList *spl, *espl, **head;
391
392 spl = SplinePointListInterpretGlif(sc->parent,path,memory,memlen,
393 sc->parent->ascent+sc->parent->descent,
394 sc->parent->ascent,
395 sc->parent->strokedfont);
396 for ( espl = spl; espl!=NULL && espl->first->next==NULL; espl=espl->next );
397 if ( espl!=NULL )
398 if ( espl->first->next->order2!=sc->layers[layer].order2 )
399 spl = SplineSetsConvertOrder(spl,sc->layers[layer].order2);
400 if ( spl==NULL ) {
401 ff_post_error(_("Too Complex or Bad"),_("I'm sorry this file is too complex for me to understand (or is erroneous)"));
402 return;
403 }
404 for ( espl=spl; espl->next!=NULL; espl = espl->next );
405 if ( layer==ly_grid )
406 head = &sc->parent->grid.splines;
407 else {
408 SCPreserveLayer(sc,layer,false);
409 head = &sc->layers[layer].splines;
410 }
411 if ( doclear ) {
412 SplinePointListsFree(*head);
413 *head = NULL;
414 }
415 espl->next = *head;
416 *head = spl;
417
418 SCCharChangedUpdate(sc,layer);
419 }
420
421 /**************************** Fig File Import *********************************/
422
slurppoints(FILE * fig,SplineFont * sf,int cnt)423 static BasePoint *slurppoints(FILE *fig,SplineFont *sf,int cnt ) {
424 BasePoint *bps = malloc((cnt+1)*sizeof(BasePoint)); /* spline code may want to add another point */
425 int x, y, i, ch;
426 real scale = sf->ascent/(8.5*1200.0);
427 real ascent = 11*1200*sf->ascent/(sf->ascent+sf->descent);
428
429 for ( i = 0; i<cnt; ++i ) {
430 fscanf(fig,"%d %d", &x, &y );
431 bps[i].x = x*scale;
432 bps[i].y = (ascent-y)*scale;
433 }
434 while ((ch=getc(fig))!='\n' && ch!=EOF);
435 return( bps );
436 }
437
slurpcolor(FILE * fig,SplineSet * sofar)438 static SplineSet *slurpcolor(FILE *fig,SplineSet *sofar) {
439 int ch;
440 while ((ch=getc(fig))!='\n' && ch!=EOF);
441 return( sofar );
442 }
443
444 static SplineSet *slurpcompoundguts(FILE *fig,SplineChar *sc, SplineSet *sofar);
445
slurpcompound(FILE * fig,SplineChar * sc,SplineSet * sofar)446 static SplineSet * slurpcompound(FILE *fig,SplineChar *sc, SplineSet *sofar) {
447 int ch;
448
449 fscanf(fig, "%*d %*d %*d %*d" );
450 while ((ch=getc(fig))!='\n' && ch!=EOF);
451 sofar = slurpcompoundguts(fig,sc,sofar);
452 return( sofar );
453 }
454
ArcSpline(SplinePoint * sp,float sa,SplinePoint * ep,float ea,float cx,float cy,float r)455 static SplinePoint *ArcSpline(SplinePoint *sp,float sa,SplinePoint *ep,float ea,
456 float cx, float cy, float r) {
457 double len;
458 double ss, sc, es, ec;
459
460 ss = sin(sa); sc = cos(sa); es = sin(ea); ec = cos(ea);
461 if ( ep==NULL )
462 ep = SplinePointCreate((double)(cx+r)*ec, (double)(cy+r)*es);
463 len = ((double)(ea-sa)/(FF_PI/2)) * (double)r * .552;
464
465 sp->nextcp.x = sp->me.x - len*ss; sp->nextcp.y = sp->me.y + len*sc;
466 ep->prevcp.x = ep->me.x + len*es; ep->prevcp.y = ep->me.y - len*ec;
467 sp->nonextcp = ep->noprevcp = false;
468 SplineMake3(sp,ep);
469 return( ep );
470 }
471
slurparc(FILE * fig,SplineChar * sc,SplineSet * sofar)472 static SplineSet * slurparc(FILE *fig,SplineChar *sc, SplineSet *sofar) {
473 int ch;
474 int sub, dir, fa, ba; /* 0 clockwise, 1 counter */
475 float cx, cy, r, sa, ea, ma;
476 float sx,sy,ex,ey;
477 int _sx,_sy,_ex,_ey;
478 SplinePoint *sp, *ep;
479 SplinePointList *spl;
480 real scale = sc->parent->ascent/(8.5*1200.0);
481 real ascent = 11*1200*sc->parent->ascent/(sc->parent->ascent+sc->parent->descent);
482
483 fscanf(fig, "%d %*d %*d %*d %*d %*d %*d %*d %*f %*d %d %d %d %f %f %d %d %*d %*d %d %d",
484 &sub, &dir, &fa, &ba, &cx, &cy, &_sx, &_sy, &_ex, &_ey );
485 while ((ch=getc(fig))!='\n' && ch!=EOF);
486 /* I ignore arrow lines */
487 if ( fa )
488 while ((ch=getc(fig))!='\n' && ch!=EOF);
489 if ( ba )
490 while ((ch=getc(fig))!='\n' && ch!=EOF);
491 sx = _sx*scale; sy = (ascent-_sy)*scale; ex = _ex*scale; ey=(ascent-_ey)*scale; cx=(double)cx*scale; cy=(ascent-(double)cy)*scale;
492 r = sqrt( (sx-cx)*(sx-cx) + (sy-cy)*(sy-cy) );
493 sa = atan2(sy-cy,sx-cx);
494 ea = atan2(ey-cy,ex-cx);
495
496 spl = chunkalloc(sizeof(SplinePointList));
497 spl->next = sofar;
498 spl->first = sp = SplinePointCreate(sx,sy);
499 spl->last = ep = SplinePointCreate(ex,ey);
500
501 if ( dir==0 ) { /* clockwise */
502 if ( ea>sa ) ea = (double)ea - 2*FF_PI;
503 ma=ceil((double)sa/(FF_PI/2)-1)*(FF_PI/2);
504 if ( RealNearish( sa,ma )) ma = (double)ma - (FF_PI/2);
505 while ( ma > ea ) {
506 sp = ArcSpline(sp,sa,NULL,ma,cx,cy,r);
507 sa = ma;
508 ma = (double)ma - (FF_PI/2);
509 }
510 sp = ArcSpline(sp,sa,ep,ea,cx,cy,r);
511 } else { /* counterclockwise */
512 if ( ea<sa ) ea = (double)ea + 2*FF_PI;
513 ma=floor((double)sa/(FF_PI/2)+1)*(FF_PI/2);
514 if ( RealNearish( sa,ma )) ma = (double)ma + (FF_PI/2);
515 while ( ma < ea ) {
516 sp = ArcSpline(sp,sa,NULL,ma,cx,cy,r);
517 sa = ma;
518 ma = (double)ma + (FF_PI/2);
519 }
520 sp = ArcSpline(sp,sa,ep,ea,cx,cy,r);
521 }
522 return( spl );
523 }
524
slurpelipse(FILE * fig,SplineChar * sc,SplineSet * sofar)525 static SplineSet * slurpelipse(FILE *fig,SplineChar *sc, SplineSet *sofar) {
526 int ch;
527 int sub, dir, cx, cy, rx, ry;
528 float angle;
529 SplinePointList *spl;
530 SplinePoint *sp;
531 real dcx,dcy,drx,dry;
532 SplineFont *sf = sc->parent;
533 real scale = sf->ascent/(8.5*1200.0);
534 real ascent = 11*1200*sf->ascent/(sf->ascent+sf->descent);
535 /* I ignore the angle */
536
537 fscanf(fig, "%d %*d %*d %*d %*d %*d %*d %*d %*f %d %f %d %d %d %d %*d %*d %*d %*d",
538 &sub, &dir, &angle, &cx, &cy, &rx, &ry );
539 while ((ch=getc(fig))!='\n' && ch!=EOF);
540
541 dcx = cx*scale; dcy = (ascent-cy)*scale;
542 drx = rx*scale; dry = ry*scale;
543
544 spl = chunkalloc(sizeof(SplinePointList));
545 spl->next = sofar;
546 spl->first = sp = chunkalloc(sizeof(SplinePoint));
547 sp->me.x = dcx; sp->me.y = dcy+dry;
548 sp->nextcp.x = sp->me.x + .552*drx; sp->nextcp.y = sp->me.y;
549 sp->prevcp.x = sp->me.x - .552*drx; sp->prevcp.y = sp->me.y;
550 spl->last = sp = chunkalloc(sizeof(SplinePoint));
551 sp->me.x = dcx+drx; sp->me.y = dcy;
552 sp->nextcp.x = sp->me.x; sp->nextcp.y = sp->me.y - .552*dry;
553 sp->prevcp.x = sp->me.x; sp->prevcp.y = sp->me.y + .552*dry;
554 SplineMake3(spl->first,sp);
555 sp = chunkalloc(sizeof(SplinePoint));
556 sp->me.x = dcx; sp->me.y = dcy-dry;
557 sp->nextcp.x = sp->me.x - .552*drx; sp->nextcp.y = sp->me.y;
558 sp->prevcp.x = sp->me.x + .552*drx; sp->prevcp.y = sp->me.y;
559 SplineMake3(spl->last,sp);
560 spl->last = sp;
561 sp = chunkalloc(sizeof(SplinePoint));
562 sp->me.x = dcx-drx; sp->me.y = dcy;
563 sp->nextcp.x = sp->me.x; sp->nextcp.y = sp->me.y + .552*dry;
564 sp->prevcp.x = sp->me.x; sp->prevcp.y = sp->me.y - .552*dry;
565 SplineMake3(spl->last,sp);
566 SplineMake3(sp,spl->first);
567 spl->last = spl->first;
568 return( spl );
569 }
570
slurppolyline(FILE * fig,SplineChar * sc,SplineSet * sofar)571 static SplineSet * slurppolyline(FILE *fig,SplineChar *sc, SplineSet *sofar) {
572 int ch;
573 int sub, cnt, fa, ba, radius; /* radius of roundrects (sub==4) */
574 BasePoint *bps;
575 BasePoint topleft, bottomright;
576 SplinePointList *spl=NULL;
577 SplinePoint *sp;
578 int i;
579
580 fscanf(fig, "%d %*d %*d %*d %*d %*d %*d %*d %*f %*d %*d %d %d %d %d",
581 &sub, &radius, &fa, &ba, &cnt );
582 /* sub==1 => polyline, 2=>box, 3=>polygon, 4=>arc-box, 5=>imported eps bb */
583 while ((ch=getc(fig))!='\n' && ch!=EOF);
584 /* I ignore arrow lines */
585 if ( fa )
586 while ((ch=getc(fig))!='\n' && ch!=EOF);
587 if ( ba )
588 while ((ch=getc(fig))!='\n' && ch!=EOF);
589 bps = slurppoints(fig,sc->parent,cnt);
590 if ( sub==5 ) /* skip picture line */
591 while ((ch=getc(fig))!='\n' && ch!=EOF);
592 else {
593 if ( sub!=1 && bps[cnt-1].x==bps[0].x && bps[cnt-1].y==bps[0].y )
594 --cnt;
595 spl = chunkalloc(sizeof(SplinePointList));
596 if ( cnt==4 && sub==4/*arc-box*/ && radius!=0 ) {
597 SplineFont *sf = sc->parent;
598 real scale = sf->ascent/(8.5*80.0), r = radius*scale; /* radii are scaled differently */
599 if ( bps[0].x>bps[2].x ) {
600 topleft.x = bps[2].x;
601 bottomright.x = bps[0].x;
602 } else {
603 topleft.x = bps[0].x;
604 bottomright.x = bps[2].x;
605 }
606 if ( bps[0].y<bps[2].y ) {
607 topleft.y = bps[2].y;
608 bottomright.y = bps[0].y;
609 } else {
610 topleft.y = bps[0].y;
611 bottomright.y = bps[2].y;
612 }
613 spl->first = SplinePointCreate(topleft.x,topleft.y-r); spl->first->pointtype = pt_tangent;
614 spl->first->nextcp.y += .552*r; spl->first->nonextcp = false;
615 spl->last = sp = SplinePointCreate(topleft.x+r,topleft.y); sp->pointtype = pt_tangent;
616 sp->prevcp.x -= .552*r; sp->noprevcp = false;
617 SplineMake3(spl->first,sp);
618 sp = SplinePointCreate(bottomright.x-r,topleft.y); sp->pointtype = pt_tangent;
619 sp->nextcp.x += .552*r; sp->nonextcp = false;
620 SplineMake3(spl->last,sp); spl->last = sp;
621 sp = SplinePointCreate(bottomright.x,topleft.y-r); sp->pointtype = pt_tangent;
622 sp->prevcp.y += .552*r; sp->noprevcp = false;
623 SplineMake3(spl->last,sp); spl->last = sp;
624 sp = SplinePointCreate(bottomright.x,bottomright.y+r); sp->pointtype = pt_tangent;
625 sp->nextcp.y -= .552*r; sp->nonextcp = false;
626 SplineMake3(spl->last,sp); spl->last = sp;
627 sp = SplinePointCreate(bottomright.x-r,bottomright.y); sp->pointtype = pt_tangent;
628 sp->prevcp.x += .552*r; sp->noprevcp = false;
629 SplineMake3(spl->last,sp); spl->last = sp;
630 sp = SplinePointCreate(topleft.x+r,bottomright.y); sp->pointtype = pt_tangent;
631 sp->nextcp.x -= .552*r; sp->nonextcp = false;
632 SplineMake3(spl->last,sp); spl->last = sp;
633 sp = SplinePointCreate(topleft.x,bottomright.y+r); sp->pointtype = pt_tangent;
634 sp->prevcp.y -= .552*r; sp->noprevcp = false;
635 SplineMake3(spl->last,sp); spl->last = sp;
636 } else {
637 for ( i=0; i<cnt; ++i ) {
638 sp = chunkalloc(sizeof(SplinePoint));
639 sp->me = sp->nextcp = sp->prevcp = bps[i];
640 sp->nonextcp = sp->noprevcp = true;
641 sp->pointtype = pt_corner;
642 if ( spl->first==NULL )
643 spl->first = sp;
644 else
645 SplineMake3(spl->last,sp);
646 spl->last = sp;
647 }
648 }
649 if ( sub!=1 ) {
650 SplineMake3(spl->last,spl->first);
651 spl->last = spl->first;
652 }
653 spl->next = sc->layers[ly_fore].splines;
654 spl->next = sofar;
655 }
656 free(bps);
657 return( spl );
658 }
659
660 /* http://dev.acm.org/pubs/citations/proceedings/graph/218380/p377-blanc/ */
661 /* X-Splines: a spline model designed for the end-user */
662 /* by Carole Blanc & Christophe Schlick */
663 /* Also based on the helpful code fragment by Andreas Baerentzen */
664 /* http://lin1.gk.dtu.dk/home/jab/software.html */
665
666 struct xspline {
667 int n; /* total number of control points */
668 BasePoint *cp; /* an array of n control points */
669 real *s; /* an array of n tension values */
670 /* for a closed spline cp[0]==cp[n-1], but we may still need to wrap a bit*/
671 unsigned int closed: 1;
672 };
673
g(real u,real q,real p)674 static real g(real u, real q, real p) {
675 return( u * (q + u * (2*q + u *( 10-12*q+10*p + u * ( 2*p+14*q-15 + u*(6-5*q-p))))) );
676 }
677
h(real u,real q)678 static real h(real u, real q) {
679 /* The paper says that h(-1)==0, but the definition of h they give */
680 /* doesn't do that. But if we negate the x^5 term it all works */
681 /* (works for the higher derivatives too) */
682 return( q*u * (1 + u * (2 - u * u * (u+2))) );
683 }
684
xsplineeval(BasePoint * ret,real t,struct xspline * xs)685 static void xsplineeval(BasePoint *ret,real t, struct xspline *xs) {
686 /* By choosing t to range between [0,n-1] we set delta in the article to 1*/
687 /* and may therefore ignore it */
688
689 /* For any value of t there are four possible points that might be */
690 /* influencing things. These are cp[k], cp[k+1], cp[k+2], cp[k+3] */
691 /* where k+1<=t<k+2 */
692 int k = floor(t-1);
693 int k0, k1, k2, k3;
694 /* now we need to find the points near us (on the + side of cp[k] & */
695 /* cp[k-1] and the - side of cp[k+2] & cp[k+3]) where the blending */
696 /* function becomes 0. This depends on the tension values */
697 /* For negative tension values it doesn't happen, the curve itself */
698 /* is changed */
699 real Tk0 = k+1 + (xs->s[k+1]>0?xs->s[k+1]:0);
700 real Tk1 = k+2 + (xs->s[k+2]>0?xs->s[k+2]:0);
701 real Tk2 = k+1 - (xs->s[k+1]>0?xs->s[k+1]:0);
702 real Tk3 = k+2 - (xs->s[k+2]>0?xs->s[k+2]:0);
703 /* Now each blending function has a "p" value that describes its shape*/
704 real p0 = 2*(k-Tk0)*(k-Tk0);
705 real p1 = 2*(k+1-Tk1)*(k+1-Tk1);
706 real p2 = 2*(k+2-Tk2)*(k+2-Tk2);
707 real p3 = 2*(k+3-Tk3)*(k+3-Tk3);
708 /* and each negative tension blending function has a "q" value */
709 real q0 = xs->s[k+1]<0?-xs->s[k+1]/2:0;
710 real q1 = xs->s[k+2]<0?-xs->s[k+2]/2:0;
711 real q2 = q0;
712 real q3 = q1;
713 /* the function f for positive s is the same as g if q==0 */
714 real A0, A1, A2, A3;
715 if ( t<=Tk0 )
716 A0 = g( (t-Tk0)/(k-Tk0), q0, p0);
717 else if ( q0>0 )
718 A0 = h( (t-Tk0)/(k-Tk0), q0 );
719 else
720 A0 = 0;
721 A1 = g( (t-Tk1)/(k+1-Tk1), q1, p1);
722 A2 = g( (t-Tk2)/(k+2-Tk2), q2, p2);
723 if ( t>=Tk3 )
724 A3 = g( (t-Tk3)/(k+3-Tk3), q3, p3);
725 else if ( q3>0 )
726 A3 = h( (t-Tk3)/(k+3-Tk3), q3 );
727 else
728 A3 = 0;
729 k0 = k; k1=k+1; k2=k+2; k3=k+3;
730 if ( k<0 ) { k0=xs->n-2; if ( !xs->closed ) A0 = 0; }
731 if ( k3>=xs->n ) { k3 -= xs->n; if ( !xs->closed ) A3 = 0; }
732 if ( k2>=xs->n ) { k2 -= xs->n; if ( !xs->closed ) A2 = 0; }
733 ret->x = A0*xs->cp[k0].x + A1*xs->cp[k1].x + A2*xs->cp[k2].x + A3*xs->cp[k3].x;
734 ret->y = A0*xs->cp[k0].y + A1*xs->cp[k1].y + A2*xs->cp[k2].y + A3*xs->cp[k3].y;
735 ret->x /= (A0+A1+A2+A3);
736 ret->y /= (A0+A1+A2+A3);
737 }
738
AdjustTs(FitPoint * mids,SplinePoint * from,SplinePoint * to)739 static void AdjustTs(FitPoint *mids,SplinePoint *from, SplinePoint *to) {
740 real len=0, sofar;
741 real lens[8];
742 int i;
743
744 lens[0] = sqrt((mids[0].p.x-from->me.x)*(mids[0].p.x-from->me.x) +
745 (mids[0].p.y-from->me.y)*(mids[0].p.y-from->me.y));
746 lens[7] = sqrt((mids[6].p.x-to->me.x)*(mids[6].p.x-to->me.x) +
747 (mids[6].p.y-to->me.y)*(mids[6].p.y-to->me.y));
748 for ( i=1; i<7; ++i )
749 lens[i] = sqrt((mids[i].p.x-mids[i-1].p.x)*(mids[i].p.x-mids[i-1].p.x) +
750 (mids[i].p.y-mids[i-1].p.y)*(mids[i].p.y-mids[i-1].p.y));
751 for ( len=0, i=0; i<8; ++i )
752 len += lens[i];
753 for ( sofar=0, i=0; i<7; ++i ) {
754 sofar += lens[i];
755 mids[i].t = sofar/len;
756 }
757 }
758
ApproximateXSpline(struct xspline * xs,int order2)759 static SplineSet *ApproximateXSpline(struct xspline *xs,int order2) {
760 size_t i, j;
761 real t;
762 FitPoint mids[7];
763 SplineSet *spl = chunkalloc(sizeof(SplineSet));
764 SplinePoint *sp;
765
766 spl->first = spl->last = chunkalloc(sizeof(SplinePoint));
767 xsplineeval(&spl->first->me,0,xs);
768 spl->first->pointtype = ( xs->s[0]==0 )?pt_corner:pt_curve;
769 for ( i=0; i<(size_t)(xs->n-1); ++i ) {
770 if ( i==(size_t)(xs->n-2) && xs->closed )
771 sp = spl->first;
772 else {
773 sp = chunkalloc(sizeof(SplinePoint));
774 sp->pointtype = ( xs->s[i+1]==0 )?pt_corner:pt_curve;
775 xsplineeval(&sp->me,i+1,xs);
776 }
777 for ( j=0, t=1./8; j<sizeof(mids)/sizeof(mids[0]); ++j, t+=1./8 ) {
778 xsplineeval((BasePoint *) &mids[j].p,i+t,xs);
779 mids[j].t = t;
780 }
781 AdjustTs(mids,spl->last,sp);
782 ApproximateSplineFromPoints(spl->last,sp,mids,sizeof(mids)/sizeof(mids[0]),order2);
783 SPAverageCps(spl->last);
784 spl->last = sp;
785 }
786 if ( !xs->closed ) {
787 spl->first->noprevcp = spl->last->nonextcp = true;
788 spl->first->prevcp = spl->first->me;
789 spl->last->nextcp = spl->last->me;
790 } else
791 SPAverageCps(spl->first);
792 return( spl );
793 }
794
slurpspline(FILE * fig,SplineChar * sc,SplineSet * sofar)795 static SplineSet * slurpspline(FILE *fig,SplineChar *sc, SplineSet *sofar) {
796 int ch;
797 int sub, cnt, fa, ba;
798 SplinePointList *spl;
799 struct xspline xs;
800 int i;
801
802 fscanf(fig, "%d %*d %*d %*d %*d %*d %*d %*d %*f %*d %d %d %d",
803 &sub, &fa, &ba, &cnt );
804 while ((ch=getc(fig))!='\n' && ch!=EOF);
805 /* I ignore arrow lines */
806 if ( fa )
807 while ((ch=getc(fig))!='\n' && ch!=EOF);
808 if ( ba )
809 while ((ch=getc(fig))!='\n' && ch!=EOF);
810 xs.n = cnt;
811 xs.cp = slurppoints(fig,sc->parent,cnt);
812 xs.s = malloc((cnt+1)*sizeof(real));
813 xs.closed = (sub&1);
814 for ( i=0; i<cnt; ++i )
815 #ifdef FONTFORGE_CONFIG_USE_DOUBLE
816 fscanf(fig,"%lf",&xs.s[i]);
817 #else
818 fscanf(fig,"%f",&xs.s[i]);
819 #endif
820 /* the spec says that the last point of a closed path will duplicate the */
821 /* first, but it doesn't seem to */
822 if ( xs.closed && ( !RealNear(xs.cp[cnt-1].x,xs.cp[0].x) ||
823 !RealNear(xs.cp[cnt-1].y,xs.cp[0].y) )) {
824 xs.n = ++cnt;
825 xs.cp[cnt-1] = xs.cp[0];
826 xs.s[cnt-1] = xs.s[0];
827 }
828 spl = ApproximateXSpline(&xs,sc->layers[ly_fore].order2);
829
830 free(xs.cp);
831 free(xs.s);
832
833 spl->next = sofar;
834 return( spl );
835 }
836
slurpcompoundguts(FILE * fig,SplineChar * sc,SplineSet * sofar)837 static SplineSet *slurpcompoundguts(FILE *fig,SplineChar *sc,SplineSet *sofar) {
838 int oc;
839 int ch;
840
841 while ( 1 ) {
842 fscanf(fig,"%d",&oc);
843 if ( feof(fig) || oc==-6 )
844 return(sofar);
845 switch ( oc ) {
846 case 6:
847 sofar = slurpcompound(fig,sc,sofar);
848 break;
849 case 0:
850 sofar = slurpcolor(fig,sofar);
851 break;
852 case 1:
853 sofar = slurpelipse(fig,sc,sofar);
854 break;
855 case 5:
856 sofar = slurparc(fig,sc,sofar);
857 break;
858 case 2:
859 sofar = slurppolyline(fig,sc,sofar);
860 break;
861 case 3:
862 sofar = slurpspline(fig,sc,sofar);
863 break;
864 case 4:
865 default:
866 /* Text is also only one line */
867 while ( (ch=getc(fig))!='\n' && ch!=EOF );
868 break;
869 }
870 }
871 return( sofar );
872 }
873
SCImportFig(SplineChar * sc,int layer,char * path,bool doclear,ImportParams * ip)874 void SCImportFig(SplineChar *sc,int layer,char *path,bool doclear,
875 ImportParams *ip) {
876 FILE *fig;
877 char buffer[100];
878 SplineSet *spl, *espl, **head;
879 int i;
880
881 fig = fopen(path,"r");
882 if ( fig==NULL ) {
883 ff_post_error(_("Can't find the file"),_("Can't find the file"));
884 return;
885 }
886 if ( fgets(buffer,sizeof(buffer),fig)==NULL || strcmp(buffer,"#FIG 3.2\n")!=0 ) {
887 ff_post_error(_("Bad xfig file"),_("Bad xfig file"));
888 fclose(fig);
889 return;
890 }
891 /* skip the header, it isn't interesting */
892 for ( i=0; i<8; ++i )
893 fgets(buffer,sizeof(buffer),fig);
894 spl = slurpcompoundguts(fig,sc,NULL);
895 if ( spl!=NULL ) {
896 if ( layer==ly_grid )
897 head = &sc->parent->grid.splines;
898 else {
899 SCPreserveLayer(sc,layer,false);
900 head = &sc->layers[layer].splines;
901 }
902 if ( doclear ) {
903 SplinePointListsFree(*head);
904 *head = NULL;
905 }
906 if ( sc->layers[ly_fore].order2 )
907 spl = SplineSetsConvertOrder(spl,true);
908 for ( espl=spl; espl->next!=NULL; espl=espl->next );
909 espl->next = *head;
910 *head = spl;
911 SCCharChangedUpdate(sc,layer);
912 }
913 fclose(fig);
914 }
915
916 /************************** Normal Image Import *******************************/
917
ImageAlterClut(GImage * image)918 GImage *ImageAlterClut(GImage *image) {
919 struct _GImage *base = image->list_len==0?image->u.image:image->u.images[0];
920 GClut *clut;
921
922 if ( base->image_type!=it_mono ) {
923 /* png b&w images come through as indexed, not mono */
924 if ( base->clut!=NULL && base->clut->clut_len==2 ) {
925 GImage *new = GImageCreate(it_mono,base->width,base->height);
926 struct _GImage *nbase = new->u.image;
927 int i,j;
928 memset(nbase->data,0,nbase->height*nbase->bytes_per_line);
929 for ( i=0; i<base->height; ++i ) for ( j=0; j<base->width; ++j )
930 if ( base->data[i*base->bytes_per_line+j] )
931 nbase->data[i*nbase->bytes_per_line+(j>>3)] |= (0x80>>(j&7));
932 nbase->clut = base->clut;
933 base->clut = NULL;
934 nbase->trans = base->trans;
935 GImageDestroy(image);
936 image = new;
937 base = nbase;
938 } else
939 return( image );
940 }
941
942 clut = base->clut;
943 if ( clut==NULL ) {
944 clut=base->clut = calloc(1,sizeof(GClut));
945 clut->clut_len = 2;
946 clut->clut[0] = 0x808080;
947 if ( !no_windowing_ui )
948 clut->clut[1] = default_background;
949 else
950 clut->clut[1] = 0xb0b0b0;
951 clut->trans_index = 1;
952 base->trans = 1;
953 } else if ( base->trans!=(Color)-1 ) {
954 clut->clut[!base->trans] = 0x808080;
955 } else if ( clut->clut[0]<clut->clut[1] ) {
956 clut->clut[0] = 0x808080;
957 clut->trans_index = 1;
958 base->trans = 1;
959 } else {
960 clut->clut[1] = 0x808080;
961 clut->trans_index = 0;
962 base->trans = 0;
963 }
964 return( image );
965 }
966
SCInsertImage(SplineChar * sc,GImage * image,real scale,real yoff,real xoff,int layer)967 void SCInsertImage(SplineChar *sc,GImage *image,real scale,real yoff,real xoff,
968 int layer) {
969 ImageList *im;
970
971 SCPreserveLayer(sc,layer,false);
972 im = malloc(sizeof(ImageList));
973 im->image = image;
974 im->xoff = xoff;
975 im->yoff = yoff;
976 im->xscale = im->yscale = scale;
977 im->selected = true;
978 im->next = sc->layers[layer].images;
979 im->bb.minx = im->xoff; im->bb.maxy = im->yoff;
980 im->bb.maxx = im->xoff + GImageGetWidth(im->image)*im->xscale;
981 im->bb.miny = im->yoff - GImageGetHeight(im->image)*im->yscale;
982 sc->layers[layer].images = im;
983 sc->parent->onlybitmaps = false;
984 SCOutOfDateBackground(sc);
985 SCCharChangedUpdate(sc,layer);
986 }
987
SCAddScaleImage(SplineChar * sc,GImage * image,bool doclear,int layer,ImportParams * ip)988 void SCAddScaleImage(SplineChar *sc,GImage *image,bool doclear, int layer,
989 ImportParams *ip) {
990 double scale = 1.0;
991
992 image = ImageAlterClut(image);
993 if ( ip->scale )
994 scale = (sc->parent->ascent+sc->parent->descent)/(real) GImageGetHeight(image);
995 if ( doclear ) {
996 ImageListsFree(sc->layers[layer].images);
997 sc->layers[layer].images = NULL;
998 }
999 SCInsertImage(sc,image,scale,sc->parent->ascent,0,layer);
1000 }
1001
FVImportImages(FontViewBase * fv,char * path,int format,int toback,bool preclear,ImportParams * ip)1002 int FVImportImages(FontViewBase *fv,char *path,int format,int toback,
1003 bool preclear, ImportParams *ip) {
1004 GImage *image;
1005 /*struct _GImage *base;*/
1006 int tot;
1007 char *start = path, *endpath=path;
1008 int i;
1009 SplineChar *sc;
1010
1011 tot = 0;
1012 for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i]) {
1013 sc = SFMakeChar(fv->sf,fv->map,i);
1014 endpath = strchr(start,';');
1015 if ( endpath!=NULL ) *endpath = '\0';
1016 if ( format==fv_image ) {
1017 image = GImageRead(start);
1018 if ( image==NULL ) {
1019 ff_post_error(_("Bad image file"),_("Bad image file: %.100s"),start);
1020 return(false);
1021 }
1022 ++tot;
1023 SCAddScaleImage(sc,image,true,toback?ly_back:ly_fore, ip);
1024 } else if ( format==fv_svg ) {
1025 SCImportSVG(sc,toback?ly_back:fv->active_layer,start,NULL,0,preclear,ip);
1026 ++tot;
1027 } else if ( format==fv_glif ) {
1028 SCImportGlif(sc,toback?ly_back:fv->active_layer,start,NULL,0,preclear,ip);
1029 ++tot;
1030 } else if ( format==fv_eps ) {
1031 SCImportPS(sc,toback?ly_back:fv->active_layer,start,preclear,ip);
1032 ++tot;
1033 } else if ( format==fv_pdf ) {
1034 SCImportPDF(sc,toback?ly_back:fv->active_layer,start,preclear,ip);
1035 ++tot;
1036 #ifndef _NO_PYTHON
1037 } else if ( format>=fv_pythonbase ) {
1038 PyFF_SCImport(sc,format-fv_pythonbase,start, toback?ly_back:fv->active_layer,preclear);
1039 ++tot;
1040 #endif
1041 }
1042 if ( endpath==NULL )
1043 break;
1044 start = endpath+1;
1045 }
1046 if ( tot==0 )
1047 ff_post_error(_("Nothing Selected"),_("You must select a glyph before you can import an image into it"));
1048 else if ( endpath!=NULL )
1049 ff_post_error(_("More Images Than Selected Glyphs"),_("More Images Than Selected Glyphs"));
1050 return( true );
1051 }
1052
FVImportImageTemplate(FontViewBase * fv,char * path,int format,int toback,bool preclear,ImportParams * ip)1053 int FVImportImageTemplate(FontViewBase *fv,char *path,int format,int toback,
1054 bool preclear, ImportParams *ip) {
1055 GImage *image;
1056 struct _GImage *base;
1057 int tot;
1058 char *ext, *name, *pt, *end;
1059 const char *dirname;
1060 int i, val;
1061 int isu=false, ise=false, isc=false;
1062 DIR *dir;
1063 struct dirent *entry;
1064 SplineChar *sc;
1065 char start [1025];
1066
1067 ext = strrchr(path,'.');
1068 name = strrchr(path,'/');
1069 if ( ext==NULL ) {
1070 ff_post_error(_("Bad Template"),_("Bad template, no extension"));
1071 return( false );
1072 }
1073 if ( name==NULL ) name=path-1;
1074 if ( name[1]=='u' ) isu = true;
1075 else if ( name[1]=='c' ) isc = true;
1076 else if ( name[1]=='e' ) ise = true;
1077 else {
1078 ff_post_error(_("Bad Template"),_("Bad template, unrecognized format"));
1079 return( false );
1080 }
1081 if ( name<path )
1082 dirname = ".";
1083 else {
1084 dirname = path;
1085 *name = '\0';
1086 }
1087
1088 if ( (dir = opendir(dirname))==NULL ) {
1089 ff_post_error(_("Nothing Loaded"),_("Nothing Loaded"));
1090 return( false );
1091 }
1092
1093 tot = 0;
1094 while ( (entry=readdir(dir))!=NULL ) {
1095 pt = strrchr(entry->d_name,'.');
1096 if ( pt==NULL )
1097 continue;
1098 if ( strmatch(pt,ext)!=0 )
1099 continue;
1100 if ( !(
1101 (isu && entry->d_name[0]=='u' && entry->d_name[1]=='n' && entry->d_name[2]=='i' && (val=strtol(entry->d_name+3,&end,16), end==pt)) ||
1102 (isu && entry->d_name[0]=='u' && (val=strtol(entry->d_name+1,&end,16), end==pt)) ||
1103 (isc && entry->d_name[0]=='c' && entry->d_name[1]=='i' && entry->d_name[2]=='d' && (val=strtol(entry->d_name+3,&end,10), end==pt)) ||
1104 (ise && entry->d_name[0]=='e' && entry->d_name[1]=='n' && entry->d_name[2]=='c' && (val=strtol(entry->d_name+3,&end,10), end==pt)) ))
1105 continue;
1106 sprintf (start, "%s/%s", dirname, entry->d_name);
1107 if ( isu ) {
1108 i = SFFindSlot(fv->sf,fv->map,val,NULL);
1109 if ( i==-1 ) {
1110 ff_post_error(_("Unicode value not in font"),_("Unicode value (%x) not in font, ignored"),val);
1111 continue;
1112 }
1113 sc = SFMakeChar(fv->sf,fv->map,i);
1114 } else {
1115 if ( val<fv->map->enccount ) {
1116 /* It's there */;
1117 } else {
1118 ff_post_error(_("Encoding value not in font"),_("Encoding value (%x) not in font, ignored"),val);
1119 continue;
1120 }
1121 sc = SFMakeChar(fv->sf,fv->map,val);
1122 }
1123 if ( format==fv_imgtemplate ) {
1124 image = GImageRead(start);
1125 if ( image==NULL ) {
1126 ff_post_error(_("Bad image file"),_("Bad image file: %.100s"),start);
1127 continue;
1128 }
1129 base = image->list_len==0?image->u.image:image->u.images[0];
1130 if ( base->image_type!=it_mono ) {
1131 ff_post_error(_("Bad image file"),_("Bad image file, not a bitmap: %.100s"),start);
1132 GImageDestroy(image);
1133 continue;
1134 }
1135 ++tot;
1136 SCAddScaleImage(sc,image,true,toback?ly_back:ly_fore,ip);
1137 } else if ( format==fv_svgtemplate ) {
1138 SCImportSVG(sc,toback?ly_back:fv->active_layer,start,NULL,0,preclear,ip);
1139 ++tot;
1140 } else if ( format==fv_gliftemplate ) {
1141 SCImportGlif(sc,toback?ly_back:fv->active_layer,start,NULL,0,preclear,ip);
1142 ++tot;
1143 } else if ( format==fv_pdftemplate ) {
1144 SCImportPDF(sc,toback?ly_back:fv->active_layer,start,preclear,ip);
1145 ++tot;
1146 } else {
1147 SCImportPS(sc,toback?ly_back:fv->active_layer,start,preclear,ip);
1148 ++tot;
1149 }
1150 }
1151 closedir(dir);
1152 if ( tot==0 )
1153 ff_post_error(_("Nothing Loaded"),_("Nothing Loaded"));
1154 return( true );
1155 }
1156