1 /* output-dr2d.c: output in DR2D format
2 
3    Copyright (C) 2002 Andrew Elia
4 
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public License
7    as published by the Free Software Foundation; either version 2.1 of
8    the License, or (at your option) any later version.
9 
10    This library is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with this library; if not, write to the Free Software
17    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18    USA. */
19 
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif /* Def: HAVE_CONFIG_H */
23 
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include "spline.h"
28 #include "color.h"
29 #include "output-dr2d.h"
30 
31 
32 /* Globals: Values are set by output_dr2d_writer() */
33 float XFactor;
34 float YFactor;
35 float LineThickness;
36 
37 #define FIXOFFS 10
38 
39 #define LF_ACTIVE 0x01
40 #define LF_DISPLAYED 0x02
41 
42 #define FT_NONE 0
43 #define FT_COLOR 1
44 
45 #define JT_NONE 0
46 #define JT_MITER 1
47 #define JT_BEVEL 2
48 #define JT_ROUND 3
49 
50 #define INDICATOR 0xFFFFFFFF
51 #define IND_SPLINE 0x00000001
52 #define IND_MOVETO 0x00000002
53 
54 struct Chunk {
55 	unsigned char ID[4];
56 	unsigned int Size;
57 	unsigned char * Data;
58 };
59 
60 static struct Chunk * BuildDRHD(int, int, int, int);
61 static struct Chunk * BuildPPRF(char *, int, char *, float);
62 static struct Chunk * BuildCMAP(spline_list_array_type);
63 static struct Chunk * BuildLAYR(void);
64 static struct Chunk * BuildDASH(void);
65 static struct Chunk * BuildBBOX(spline_list_type, int);
66 static struct Chunk * BuildATTR(at_color_type, int, struct Chunk *);
67 static int GetCMAPEntry(at_color_type, struct Chunk *);
68 static int CountSplines(spline_list_type);
69 static int SizeFloat(float, char *);
70 static void ShortAsBytes(int, unsigned char *);
71 static void IntAsBytes(int, unsigned char *);
72 static void FloatAsIEEEBytes(float, unsigned char *);
73 /* static void ieee2flt(long *, float *); */
74 static void flt2ieee(float *, unsigned char *);
75 static void FreeChunk(struct Chunk *);
76 static void FreeChunks(struct Chunk **, int);
77 static int TotalSizeChunks(struct Chunk **, int);
78 static int SizeChunk(struct Chunk *);
79 static void PushPolyPoint(unsigned char *, int *, float, float);
80 static void PushPolyIndicator(unsigned char *, int *, unsigned int);
81 static struct Chunk ** GeneratexPLY(struct Chunk *, spline_list_array_type, int);
82 
BuildCMAP(spline_list_array_type shape)83 static struct Chunk * BuildCMAP(spline_list_array_type shape) {
84 	unsigned this_list;
85 	unsigned this_list_length;
86 	int ListSize, MaxListSize;
87 	int WalkCol, FoundCol;
88 	unsigned char Red, Green, Blue;
89 	unsigned char * CMAP;
90 	unsigned char * IndexCol;
91 	struct Chunk * CMAPChunk;
92 
93 	MaxListSize = SPLINE_LIST_ARRAY_LENGTH(shape);
94 
95 	if ((CMAPChunk = (struct Chunk *) malloc(sizeof(struct Chunk))) == NULL) {
96 		fprintf(stderr, "Insufficient memory to allocate CMAP chunk\n");
97 		return NULL;
98 	}
99 
100 	if ((CMAP = (unsigned char *) malloc(MaxListSize * 3)) == NULL) {
101 		fprintf(stderr, "Insufficient memory to allocate colour map (size %d)\n", MaxListSize);
102 		free(CMAPChunk);
103 		return NULL;
104 	}
105 
106 	ListSize = 0;
107 	this_list_length = SPLINE_LIST_ARRAY_LENGTH(shape);
108 	for (this_list = 0; this_list < this_list_length; this_list++) {
109 		spline_list_type list = SPLINE_LIST_ARRAY_ELT(shape, this_list);
110         color_type curr_color = curr_color = (list.clockwise && shape.background_color != NULL)? *(shape.background_color) : list.color;
111 
112 		Red = curr_color.r;
113 		Green = curr_color.g;
114 		Blue = curr_color.b;
115 
116 		FoundCol = 0;
117 		for (WalkCol = 0; WalkCol < ListSize; WalkCol++) {
118 			IndexCol = CMAP + (WalkCol * 3);
119 			if ((*IndexCol == Red) && (*(IndexCol + 1) == Green) && (*(IndexCol + 2) == Blue)) {
120 				FoundCol = 1;
121 				break;
122 			}
123 		}
124 
125 		if (FoundCol == 0) {
126 			IndexCol = CMAP + (ListSize * 3);
127 			*IndexCol = Red;
128 			*(IndexCol + 1) = Green;
129 			*(IndexCol + 2) = Blue;
130 			++ListSize;
131 		}
132 	}
133 
134 	strncpy(CMAPChunk->ID, "CMAP", 4);
135 	CMAPChunk->Size = ListSize * 3;
136 	CMAPChunk->Data = CMAP;
137 
138 	return CMAPChunk;
139 }
140 
GetCMAPEntry(at_color_type colour,struct Chunk * CMAPChunk)141 static int GetCMAPEntry(at_color_type colour, struct Chunk * CMAPChunk) {
142 	int WalkCol, ListSize;
143 	unsigned char Red, Green, Blue;
144 	unsigned char * IndexCol;
145 	unsigned char * CMAPTable;
146 
147 	ListSize = (CMAPChunk->Size) / 3;
148 	CMAPTable = CMAPChunk->Data;
149 
150 	Red = colour.r;
151 	Green = colour.g;
152 	Blue = colour.b;
153 
154 	for (WalkCol = 0; WalkCol < ListSize; WalkCol++) {
155 		IndexCol = CMAPTable + (WalkCol * 3);
156 		if ((*IndexCol == Red) && (*(IndexCol + 1) == Green) && (*(IndexCol + 2) == Blue)) {
157 			return WalkCol;
158 		}
159 	}
160 
161 	return -1;
162 }
163 
BuildBBOX(spline_list_type list,int height)164 static struct Chunk * BuildBBOX(spline_list_type list, int height) {
165 	unsigned this_spline;
166 	unsigned this_spline_length;
167 	float x1, y1, x2, y2;
168 	float ex, ey;
169 	struct Chunk * BBOXChunk;
170 	unsigned char * BBOXData;
171 	spline_type s;
172 
173 	if ((BBOXChunk = (struct Chunk *) malloc(sizeof(struct Chunk))) == NULL) {
174 		fprintf(stderr, "Insufficient memory to allocate BBOX chunk\n");
175 		return NULL;
176 	}
177 
178 	if ((BBOXData = (unsigned char *) malloc(16)) == NULL) {
179 		fprintf(stderr, "Insufficient memory to allocate BBOX data\n");
180 		free(BBOXChunk);
181 		return NULL;
182 	}
183 
184 	s = SPLINE_LIST_ELT(list, 0);
185 
186 	x1 = START_POINT(s).x;
187 	y1 = START_POINT(s).y;
188 	x2 = START_POINT(s).x;
189 	y2 = START_POINT(s).y;
190 
191 	this_spline_length = SPLINE_LIST_LENGTH(list);
192 	for (this_spline = 0; this_spline < this_spline_length; this_spline++) {
193 		s = SPLINE_LIST_ELT(list, this_spline);
194 		ex = END_POINT(s).x;
195 		ey = height - END_POINT(s).y;
196 
197 		if (x1 > ex) {
198 			x1 = ex;
199 		}
200 
201 		if (y1 > ey) {
202 			y1 = ey;
203 		}
204 
205 		if (x2 < ex) {
206 			x2 = ex;
207 		}
208 
209 		if (y2 < ey) {
210 			y2 = ey;
211 		}
212 	}
213 
214 	FloatAsIEEEBytes(x1 * XFactor, BBOXData);
215 	FloatAsIEEEBytes(y1 * YFactor, BBOXData + 4);
216 	FloatAsIEEEBytes(x2 * XFactor, BBOXData + 8);
217 	FloatAsIEEEBytes(y2 * YFactor, BBOXData + 12);
218 
219 	strncpy(BBOXChunk->ID, "BBOX", 4);
220 	BBOXChunk->Size = 16;
221 	BBOXChunk->Data = BBOXData;
222 
223 	return BBOXChunk;
224 }
225 
BuildATTR(at_color_type colour,int StrokeOrFill,struct Chunk * CMAPChunk)226 static struct Chunk * BuildATTR(at_color_type colour, int StrokeOrFill, struct Chunk * CMAPChunk) {
227 	struct Chunk * ATTRChunk;
228 	unsigned char * ATTRData;
229 	int ColourIndex;
230 
231 	if ((ATTRChunk = (struct Chunk *) malloc(sizeof(struct Chunk))) == NULL) {
232 		fprintf(stderr, "Insufficient memory to allocate ATTR chunk\n");
233 		return NULL;
234 	}
235 
236 	if ((ATTRData = (unsigned char *) malloc(14)) == NULL) {
237 		fprintf(stderr, "Insufficient memory to allocate ATTR data\n");
238 		free(ATTRChunk);
239 		return NULL;
240 	}
241 
242 	ColourIndex = GetCMAPEntry(colour, CMAPChunk);
243 
244 	ATTRData[0] = (StrokeOrFill) ? FT_NONE : FT_COLOR;
245 	ATTRData[1] = JT_ROUND;
246 	ATTRData[2] = 1;
247 	ATTRData[3] = 0;
248 	ShortAsBytes(ColourIndex, ATTRData + 4);
249 	ShortAsBytes(ColourIndex, ATTRData + 6);
250 	ShortAsBytes(0, ATTRData + 8);
251 	FloatAsIEEEBytes(LineThickness, ATTRData + 10);
252 
253 	strncpy(ATTRChunk->ID, "ATTR", 4);
254 	ATTRChunk->Size = 14;
255 	ATTRChunk->Data = ATTRData;
256 
257 	return ATTRChunk;
258 }
259 
BuildDRHD(int x1,int y1,int x2,int y2)260 static struct Chunk * BuildDRHD(int x1, int y1, int x2, int y2) {
261 	struct Chunk * DRHDChunk;
262 	unsigned char * DRHDData;
263 
264 	if ((DRHDChunk = (struct Chunk *) malloc(sizeof(struct Chunk))) == NULL) {
265 		fprintf(stderr, "Insufficient memory to allocate DRHD chunk\n");
266 		return NULL;
267 	}
268 
269 	if ((DRHDData = (unsigned char *) malloc(16)) == NULL) {
270 		fprintf(stderr, "Insufficient memory to allocate DRHD data\n");
271 		free(DRHDChunk);
272 		return NULL;
273 	}
274 
275 	FloatAsIEEEBytes(x1 * XFactor, DRHDData);
276 	FloatAsIEEEBytes(y1 * YFactor, DRHDData + 4);
277 	FloatAsIEEEBytes(x2 * XFactor, DRHDData + 8);
278 	FloatAsIEEEBytes(y2 * YFactor, DRHDData + 12);
279 
280 	strncpy(DRHDChunk->ID, "DRHD", 4);
281 	DRHDChunk->Size = 16;
282 	DRHDChunk->Data = DRHDData;
283 
284 	return DRHDChunk;
285 }
286 
BuildPPRF(char * Units,int Portrait,char * PageType,float GridSize)287 static struct Chunk * BuildPPRF(char * Units, int Portrait, char * PageType, float GridSize) {
288 	struct Chunk * PPRFChunk;
289 	char * PPRFData;
290 	char * PPRFPos;
291 	int ChunkSize;
292 
293 	if ((PPRFChunk = (struct Chunk *) malloc(sizeof(struct Chunk))) == NULL) {
294 		fprintf(stderr, "Insufficient memory to allocate PPRF chunk\n");
295 		return NULL;
296 	}
297 
298 	ChunkSize = strlen("Units=") + strlen(Units) + 1;
299 	ChunkSize += strlen("Portrait=") + (Portrait ? 4 : 5) + 1;
300 	ChunkSize += strlen("PageType=") + strlen(PageType) + 1;
301 	ChunkSize += strlen("GridSize=") + SizeFloat(GridSize, "%f") + 1;
302 
303 	if ((PPRFData = (char *) malloc(ChunkSize)) == NULL) {
304 		fprintf(stderr, "Insufficient memory to allocate PPRF data\n");
305 		free(PPRFChunk);
306 		return NULL;
307 	}
308 
309 	PPRFPos = PPRFData;
310 	sprintf(PPRFPos, "Units=%s", Units);
311 	PPRFPos += strlen(PPRFPos) + 1;
312 	sprintf(PPRFPos, "Portrait=%s", (Portrait ? "True" : "False"));
313 	PPRFPos += strlen(PPRFPos) + 1;
314 	sprintf(PPRFPos, "PageType=%s", PageType);
315 	PPRFPos += strlen(PPRFPos) + 1;
316 	sprintf(PPRFPos, "GridSize=%f", GridSize);
317 
318 	strncpy(PPRFChunk->ID, "PPRF", 4);
319 	PPRFChunk->Size = ChunkSize;
320 	PPRFChunk->Data = (unsigned char *) PPRFData;
321 
322 	return PPRFChunk;
323 }
324 
BuildLAYR()325 static struct Chunk * BuildLAYR() {
326 	struct Chunk * LAYRChunk;
327 	unsigned char * LAYRData;
328 
329 	if ((LAYRChunk = (struct Chunk *) malloc(sizeof(struct Chunk))) == NULL) {
330 		fprintf(stderr, "Insufficient memory to allocate LAYR chunk\n");
331 		return NULL;
332 	}
333 
334 	if ((LAYRData = (unsigned char *) malloc(20)) == NULL) {
335 		fprintf(stderr, "Insufficient memory to allocate LAYR data\n");
336 		free(LAYRChunk);
337 		return NULL;
338 	}
339 
340 	ShortAsBytes(0, LAYRData);
341 	memset(LAYRData + 2, (char) NULL, 16);
342 	strcpy(LAYRData + 2, "Default layer");
343 	*(LAYRData + 18) = LF_ACTIVE | LF_DISPLAYED;
344 	*(LAYRData + 19) = 0;
345 
346 	strncpy(LAYRChunk->ID, "LAYR", 4);
347 	LAYRChunk->Size = 20;
348 	LAYRChunk->Data = LAYRData;
349 
350 	return LAYRChunk;
351 }
352 
BuildDASH(void)353 static struct Chunk * BuildDASH(void) {
354 	struct Chunk * DASHChunk;
355 	unsigned char * DASHData;
356 
357 	if ((DASHChunk = (struct Chunk *) malloc(sizeof(struct Chunk))) == NULL) {
358 		fprintf(stderr, "Insufficient memory to allocate DASH chunk\n");
359 		return NULL;
360 	}
361 
362 	if ((DASHData = (unsigned char *) malloc(4)) == NULL) {
363 		fprintf(stderr, "Insufficient memory to allocate DASH data\n");
364 		free(DASHChunk);
365 		return NULL;
366 	}
367 
368 	ShortAsBytes(1, DASHData);
369 	ShortAsBytes(0, DASHData + 2);
370 
371 	strncpy(DASHChunk->ID, "DASH", 4);
372 	DASHChunk->Size = 4;
373 	DASHChunk->Data = DASHData;
374 
375 	return DASHChunk;
376 }
377 
GeneratexPLY(struct Chunk * CMAP,spline_list_array_type shape,int height)378 static struct Chunk ** GeneratexPLY(struct Chunk * CMAP, spline_list_array_type shape, int height) {
379 	unsigned this_list;
380 	unsigned this_list_length;
381 	unsigned this_spline;
382 	unsigned this_spline_length;
383 	spline_type s;
384 	struct Chunk ** ChunkList;
385 	struct Chunk * PolyChunk;
386 	int ListPoint, PolySize, PolyPoint, NumPoints;
387 	int StrokeOrFill;
388 	unsigned char * PolyData;
389 
390 	this_list_length = SPLINE_LIST_ARRAY_LENGTH(shape);
391 
392 	/* We store three chunks for every spline (one for BBOX, one for ATTR, and one for xPLY) */
393 	if ((ChunkList = (struct Chunk **) malloc(sizeof(struct Chunk) * (this_list_length * 3))) == NULL) {
394 		fprintf(stderr, "Insufficient memory to allocate chunk list\n");
395 		return NULL;
396 	}
397 
398 	ListPoint = 0;
399 	for (this_list = 0; this_list < this_list_length; this_list++) {
400 		spline_list_type list = SPLINE_LIST_ARRAY_ELT(shape, this_list);
401 		spline_type first = SPLINE_LIST_ELT(list, 0);
402         color_type curr_color = curr_color = (list.clockwise && shape.background_color != NULL)? *(shape.background_color) : list.color;
403 
404 		StrokeOrFill = (shape.centerline || list.open);
405 		this_spline_length = SPLINE_LIST_LENGTH(list);
406 
407 		ChunkList[ListPoint++] = BuildBBOX(list, height);
408 		ChunkList[ListPoint++] = BuildATTR(curr_color, StrokeOrFill, CMAP);
409 
410 		if ((PolyChunk = (struct Chunk *) malloc(sizeof(struct Chunk))) == NULL) {
411 			fprintf(stderr, "Insufficient memory to allocate xPLY chunk\n");
412 			FreeChunks(ChunkList, ListPoint);
413 			return NULL;
414 		}
415 
416 		NumPoints = CountSplines(list);
417 
418 		/* Store an extra 2 bytes for length header */
419 		PolySize = (NumPoints << 3) + 2;
420 		if ((PolyData = (unsigned char *) malloc(PolySize)) == NULL) {
421 			fprintf(stderr, "Insufficient memory to allocate xPLY data\n");
422 			free(PolyChunk);
423 			free(PolyData);
424 			FreeChunks(ChunkList, ListPoint);
425 			return NULL;
426 		}
427 
428 		ChunkList[ListPoint++] = PolyChunk;
429 		strncpy(PolyChunk->ID, (StrokeOrFill) ? "OPLY" : "CPLY", 4);
430 		PolyChunk->Size = PolySize;
431 		PolyChunk->Data = PolyData;
432 
433 		ShortAsBytes(NumPoints, PolyData);
434 		PolyPoint = 2;
435 
436 		if (SPLINE_DEGREE(first) == LINEARTYPE) {
437 			PushPolyPoint(PolyData, &PolyPoint, START_POINT(first).x, height - START_POINT(first).y);
438 		}
439 
440 		for (this_spline = 0; this_spline < this_spline_length; this_spline++) {
441 			s = SPLINE_LIST_ELT(list, this_spline);
442 
443 			if (SPLINE_DEGREE(s) == LINEARTYPE) {
444 				PushPolyPoint(PolyData, &PolyPoint, END_POINT(s).x, height - END_POINT(s).y);
445 			} else {
446 				PushPolyIndicator(PolyData, &PolyPoint, IND_SPLINE);
447 				PushPolyPoint(PolyData, &PolyPoint, START_POINT(s).x, height - START_POINT(s).y);
448 				PushPolyPoint(PolyData, &PolyPoint, CONTROL1(s).x, height - CONTROL1(s).y);
449 				PushPolyPoint(PolyData, &PolyPoint, CONTROL2(s).x, height - CONTROL2(s).y);
450 				PushPolyPoint(PolyData, &PolyPoint, END_POINT(s).x, height - END_POINT(s).y);
451 			}
452 		}
453 	}
454 
455 	return ChunkList;
456 }
457 
CountSplines(spline_list_type list)458 static int CountSplines(spline_list_type list) {
459 	unsigned this_spline;
460 	unsigned this_spline_length;
461 	int Total;
462 
463 	Total = 0;
464 
465 	if (SPLINE_DEGREE(SPLINE_LIST_ELT(list, 0)) == LINEARTYPE) {
466 		++Total;
467 	}
468 
469 	this_spline_length = SPLINE_LIST_LENGTH(list);
470 	for (this_spline = 0; this_spline < this_spline_length; this_spline++) {
471 		if (SPLINE_DEGREE(SPLINE_LIST_ELT(list, this_spline)) == LINEARTYPE) {
472 			++Total;
473 		} else {
474 			Total += 5;
475 		}
476 	}
477 
478 	return Total;
479 }
480 
PushPolyPoint(unsigned char * PolyData,int * PolyPoint,float x,float y)481 static void PushPolyPoint(unsigned char * PolyData, int * PolyPoint, float x, float y) {
482 	int PolyLocal;
483 
484 	PolyLocal = *PolyPoint;
485 
486 	FloatAsIEEEBytes(x * XFactor, PolyData + PolyLocal);
487 	PolyLocal += 4;
488 	FloatAsIEEEBytes(y * YFactor, PolyData + PolyLocal);
489 
490 	*PolyPoint = PolyLocal + 4;
491 }
492 
PushPolyIndicator(unsigned char * PolyData,int * PolyPoint,unsigned int flags)493 static void PushPolyIndicator(unsigned char * PolyData, int * PolyPoint, unsigned int flags) {
494 	int PolyLocal;
495 
496 	PolyLocal = *PolyPoint;
497 
498 	IntAsBytes(INDICATOR, PolyData + PolyLocal);
499 	PolyLocal += 4;
500 	IntAsBytes(flags, PolyData + PolyLocal);
501 
502 	*PolyPoint = PolyLocal + 4;
503 }
504 
WriteChunk(FILE * file,struct Chunk * Chunk)505 static void WriteChunk(FILE * file, struct Chunk * Chunk) {
506 	unsigned char SizeBytes[4];
507 	int Size;
508 
509 	Size = Chunk->Size;
510 	IntAsBytes(Size, SizeBytes);
511 
512 	fwrite(Chunk->ID, 4, 1, file);
513 	fwrite(SizeBytes, 4, 1, file);
514 	fwrite(Chunk->Data, Size, 1, file);
515 	if (Size & 0x01) {
516 		fprintf(file, "%c", (char) NULL);
517 	}
518 }
519 
WriteChunks(FILE * file,struct Chunk ** ChunkList,int NumChunks)520 static void WriteChunks(FILE * file, struct Chunk ** ChunkList, int NumChunks) {
521 	int WalkChunks;
522 
523 	for (WalkChunks = 0; WalkChunks < NumChunks; WalkChunks++) {
524 		WriteChunk(file, ChunkList[WalkChunks]);
525 	}
526 }
527 
TotalSizeChunks(struct Chunk ** ChunkList,int NumChunks)528 static int TotalSizeChunks(struct Chunk ** ChunkList, int NumChunks) {
529 	int WalkChunks;
530 	int Size;
531 	int Total;
532 
533 	Total = 0;
534 	for (WalkChunks = 0; WalkChunks < NumChunks; WalkChunks++) {
535 		/* 4 bytes for ID and 4 bytes for length */
536 		Size = ChunkList[WalkChunks]->Size;
537 		Size += Size & 0x01;
538 		Total += (Size) + 8;
539 	}
540 
541 	return Total;
542 }
543 
SizeChunk(struct Chunk * ThisChunk)544 static int SizeChunk(struct Chunk * ThisChunk) {
545 	int Size;
546 
547 	Size = ThisChunk->Size;
548 	Size += Size & 0x01;
549 
550 	return Size;
551 }
552 
FreeChunk(struct Chunk * ThisChunk)553 static void FreeChunk(struct Chunk * ThisChunk) {
554 	free(ThisChunk->Data);
555 	free(ThisChunk);
556 }
557 
FreeChunks(struct Chunk ** ChunkList,int NumChunks)558 static void FreeChunks(struct Chunk ** ChunkList, int NumChunks) {
559 	int WalkChunks;
560 
561 	for (WalkChunks = 0; WalkChunks < NumChunks; WalkChunks++) {
562 		FreeChunk(ChunkList[WalkChunks]);
563 	}
564 }
565 
output_dr2d_writer(FILE * file,at_string name,int llx,int lly,int urx,int ury,at_output_opts_type * opts,spline_list_array_type shape,at_msg_func msg_func,at_address msg_data)566 int output_dr2d_writer(FILE * file, at_string name, int llx, int lly, int urx, int ury,
567 		       at_output_opts_type * opts,
568 		       spline_list_array_type shape, at_msg_func msg_func, at_address msg_data)
569 {
570 	int width = urx - llx;
571 	int height = ury - lly;
572 	int NumSplines, FORMSize;
573 	int Portrait;
574 	struct Chunk * DRHDChunk;
575 	struct Chunk * PPRFChunk;
576 	struct Chunk * LAYRChunk;
577 	struct Chunk * DASHChunk;
578 	struct Chunk * CMAPChunk;
579 	struct Chunk ** ChunkList;
580 	unsigned char SizeBytes[4];
581 
582 	Portrait = width < height;
583 
584 	if (Portrait) {
585 		XFactor = ((float)11.6930 / (float) width) * (1 << FIXOFFS);
586 		YFactor = XFactor;
587 	} else {
588 		YFactor = ((float)8.2681 / (float) height) * (1 << FIXOFFS);
589 		XFactor = YFactor;
590 	}
591 
592 	LineThickness = (float)1.0 / opts->dpi;
593 
594 	DRHDChunk = BuildDRHD(llx, lly, urx, ury);
595 	PPRFChunk = BuildPPRF("Inch", Portrait, "A4", 1.0);
596 	LAYRChunk = BuildLAYR();
597 	DASHChunk = BuildDASH();
598 	CMAPChunk = BuildCMAP(shape);
599 
600 	ChunkList = GeneratexPLY(CMAPChunk, shape, height);
601 
602 	NumSplines = SPLINE_LIST_ARRAY_LENGTH(shape) * 3;
603 	FORMSize = 4 + (SizeChunk(DRHDChunk) + 8) + (SizeChunk(PPRFChunk) + 8) + (SizeChunk(LAYRChunk) + 8) + (SizeChunk(DASHChunk) + 8) + (SizeChunk(CMAPChunk) + 8) + TotalSizeChunks(ChunkList, NumSplines);
604 
605 	IntAsBytes(FORMSize, SizeBytes);
606 	fprintf(file, "FORM");
607 	fwrite(SizeBytes, 4, 1, file);
608 	fprintf(file, "DR2D");
609 
610 	WriteChunk(file, DRHDChunk);
611 	FreeChunk(DRHDChunk);
612 	WriteChunk(file, PPRFChunk);
613 	FreeChunk(PPRFChunk);
614 	WriteChunk(file, LAYRChunk);
615 	FreeChunk(LAYRChunk);
616 	WriteChunk(file, DASHChunk);
617 	FreeChunk(DASHChunk);
618 	WriteChunk(file, CMAPChunk);
619 	FreeChunk(CMAPChunk);
620 	WriteChunks(file, ChunkList, NumSplines);
621 	FreeChunks(ChunkList, NumSplines);
622 
623 	return 0;
624 }
625 
SizeFloat(float f,char * Format)626 static int SizeFloat(float f, char * Format) {
627 	char FloatString[100];
628 
629 	return (sprintf(FloatString, Format, f));
630 }
631 
IntAsBytes(int value,unsigned char * bytes)632 static void IntAsBytes(int value, unsigned char * bytes) {
633 	*bytes = (value >> 24) & 0xFF;
634 	*(bytes + 1) = (value >> 16) & 0xFF;
635 	*(bytes + 2) = (value >> 8) & 0xFF;
636 	*(bytes + 3) = value & 0xFF;
637 }
638 
ShortAsBytes(int value,unsigned char * bytes)639 static void ShortAsBytes(int value, unsigned char * bytes) {
640 	*(bytes + 0) = (value >> 8) & 0xFF;
641 	*(bytes + 1) = value & 0xFF;
642 }
643 
FloatAsIEEEBytes(float value,unsigned char * bytes)644 static void FloatAsIEEEBytes(float value, unsigned char * bytes) {
645 	flt2ieee(&value, bytes);
646 }
647 
flt2ieee(float * flt,unsigned char * bytes)648 static void flt2ieee(float * flt, unsigned char * bytes) {
649 	long RealMant, RealMask, RealExp;
650 	long MoveExp;
651 
652 	RealMant = (long) *flt;
653 
654 	*bytes = 0;
655 	*(bytes + 1) = 0;
656 	*(bytes + 2) = 0;
657 	*(bytes + 3) = 0;
658 
659 	if (RealMant) {
660 		if (RealMant < 0) {
661 			*bytes |= 0x80;
662 			RealMant = -RealMant;
663 		}
664 
665 		for (RealMask = 0x40000000, RealExp = 31; RealMask; RealMask >>= 1, RealExp--) {
666 			if (RealMant & RealMask) {
667 				break;
668 			}
669 		}
670 
671 		if (RealExp > 24) {
672 			RealMant >>= RealExp - 24;
673 		} else {
674 			RealMant <<= 24 - RealExp;
675 		}
676 		RealExp -= FIXOFFS;
677 		RealExp += 126;
678 
679 		MoveExp = RealExp << 23;
680 		*bytes |= (MoveExp >> 24) & 0x7F;
681 		*(bytes + 1) |= ((MoveExp >> 16) & 0x80) | ((RealMant >> 16) & 0x7F);
682 		*(bytes + 2) |= (RealMant >> 8) & 0xFF;
683 		*(bytes + 3) |= RealMant & 0xFF;
684 	}
685 }
686