21 #define FILE_BUFFER_CAPACITY (1024*4)
28 static const unsigned long Pow10[] = {1,10,100,1000,10000,100000,
29 1000000,10000000,100000000};
37 ErrorMessage(
"Pen::DrawLine callback has not been defined.\n");
43 static int StubDrawQBezier(
pen *Pen,
float x1,
float y1,
44 float x2,
float y2,
float x3,
float y3)
46 float L, t, xlast, ylast, xcur, ycur;
52 ErrorMessage(
"Pen::DrawQBezier callback has not been defined.\n");
58 NumLines = (int)(L*0.04);
59 NumLines = (NumLines < 4) ? 4 : NumLines;
63 for(i = 1; i <= NumLines; i++)
65 t = ((float)i)/NumLines;
66 xcur = (1 - t)*((1 - t)*x1 + 2*t*x2) + t*t*x3;
67 ycur = (1 - t)*((1 - t)*y1 + 2*t*y2) + t*t*y3;
68 Pen->
DrawLine(Pen, xlast, ylast, xcur, ycur);
78 static int StubDrawEllipse(
pen *Pen,
79 float x,
float y,
float rx,
float ry,
float Theta)
81 const float CosTheta = (float)cos(Theta), SinTheta = (float)sin(Theta);
82 float C, t, xlast, ylast, xcur, ycur;
88 ErrorMessage(
"Pen::DrawEllipse callback has not been defined.\n");
94 NumLines = (int)(C*0.07);
95 NumLines = (NumLines < 8) ? 8 : NumLines;
97 xlast = x + CosTheta*rx;
98 ylast = y - SinTheta*rx;
100 for(i = 1; i <= NumLines; i++)
102 t = (i < NumLines) ? ((
float)i)*
M_2PI/NumLines : 0;
103 xcur = x + CosTheta*rx*cos(t) + SinTheta*ry*sin(t);
104 ycur = y - SinTheta*rx*cos(t) + CosTheta*ry*sin(t);
105 Pen->
DrawLine(Pen, xlast, ylast, xcur, ycur);
124 {1, 0, 0, 1, 0, 0}, NULL, 0, 0, {0, 0, 0}, -1,
125 NULL, StubDrawLine, StubDrawQBezier, StubDrawEllipse};
155 return (Pen) ? Pen->
File : NULL;
169 return (Pen && Pen->
DrawLine(Pen, x1, y1, x2, y2));
182 && Pen->
DrawLine(Pen, x1, y1, x2, y1)
183 && Pen->
DrawLine(Pen, x2, y1, x2, y2)
184 && Pen->
DrawLine(Pen, x2, y2, x1, y2)
185 && Pen->
DrawLine(Pen, x1, y2, x1, y1));
198 float x2,
float y2,
float x3,
float y3)
200 return (Pen && Pen->
DrawQBezier(Pen, x1, y1, x2, y2, x3, y3));
215 return (Pen && Pen->
DrawEllipse(Pen, x, y, r, r, 0));
230 float x,
float y,
float rx,
float ry,
float Theta)
232 return (Pen && Pen->
DrawEllipse(Pen, x, y, rx, ry, Theta));
248 unsigned long Digit, Whole, Frac;
263 Whole = (
unsigned long)Value;
265 Frac = (
unsigned long)(Pow10[NumDigits]*(Value - Whole) + 0.5f);
268 if(Frac >= Pow10[NumDigits])
271 Frac -= Pow10[NumDigits];
274 fprintf(File,
"%lu", Whole);
281 for(i = NumDigits - 1; Frac > 0 && i >= 0; i--)
283 Digit = Frac / Pow10[i];
285 putc(
'0' + (
char)Digit, File);
290 fprintf(File,
"%lu", (
unsigned long)(Value + 0.5f));
357 double c,
double d,
double e,
double f)
379 Pen->
Trans = NewTrans;
417 const double CosTheta = cos(Theta);
418 const double SinTheta = sin(Theta);
462 if(Pen->
Palette[i][0] == Color[0]
463 && Pen->
Palette[i][1] == Color[1]
464 && Pen->
Palette[i][2] == Color[2])
495 float (*NewPalette)[3];
496 int NewCapacity = NumPalette + 1 + (NumPalette + 5)/10;
499 sizeof(
float)*3*NewCapacity)))
506 for(i = 0; i < 3; i++)
507 Pen->
Palette[NumPalette][i] = Color[i];
524 Pen->
Color[0] = Color[0];
525 Pen->
Color[1] = Color[1];
526 Pen->
Color[2] = Color[2];
548 const double CosTheta = cos(*Theta), SinTheta = sin(*Theta);
549 double XTrans, YTrans, A[2][2], ThetaTrans, RxTrans, RyTrans, Phi;
552 A[0][0] = (Trans.
a*CosTheta - Trans.
c*SinTheta)*(*rx);
553 A[1][0] = (Trans.
b*CosTheta - Trans.
d*SinTheta)*(*rx);
554 A[0][1] = (Trans.
a*SinTheta + Trans.
c*CosTheta)*(*ry);
555 A[1][1] = (Trans.
b*SinTheta + Trans.
d*CosTheta)*(*ry);
558 Svd2x2(&ThetaTrans, &RxTrans, &RyTrans, &Phi, &Sign1, &Sign2, A);
561 if(fabs(fabs(ThetaTrans) -
M_PI/2) < 1e-12)
563 *rx = (float)RyTrans;
564 *ry = (float)RxTrans;
569 *rx = (float)RxTrans;
570 *ry = (float)RyTrans;
571 *Theta = (float)ThetaTrans;
574 XTrans = Trans.
a*(*x) + Trans.
c*(*y) + Trans.
e;
575 YTrans = Trans.
b*(*x) + Trans.
d*(*y) + Trans.
f;
594 Temp = Trans.
a*x1 + Trans.
c*y1 + Trans.
e;
595 y1 = Trans.
b*x1 + Trans.
d*y1 + Trans.
f;
597 Temp = Trans.
a*x2 + Trans.
c*y2 + Trans.
e;
598 y2 = Trans.
b*x2 + Trans.
d*y2 + Trans.
f;
600 Temp = Trans.
a*x3 + Trans.
c*y3 + Trans.
e;
601 y3 = Trans.
b*x3 + Trans.
d*y3 + Trans.
f;
605 return sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2))
606 + sqrt((x2 - x3)*(x2 - x3) + (y2 - y3)*(y2 - y3));
622 Temp = (rx - ry)/(rx + ry);
624 return M_PI*(rx + ry)*(1 + 3*Temp/(10 + sqrt(4 - 3*Temp)));
641 static float fpart(
float x)
643 return (
float)(x - floor(x));
647 static void PlotPixel(
float *Image,
int Width,
int Height,
int x,
int y,
648 float Alpha,
const float *Color)
650 if(0 <= x && x < Width && 0 <= y && y < Height)
652 const float CAlpha = 1 - Alpha;
654 Image += 3*(x + Width*y);
655 Image[0] = CAlpha*Image[0] + Alpha*Color[0];
656 Image[1] = CAlpha*Image[1] + Alpha*Color[1];
657 Image[2] = CAlpha*Image[2] + Alpha*Color[2];
668 static int RasterDrawLine(
pen *Pen,
float x1,
float y1,
float x2,
float y2)
670 float *Image, *Color;
671 float yend, Gap, dx, dy, Gradient, y, Temp;
672 int Width, Height, xend, ix, iy, ix1, iy1, ix2, iy2, Swapped = 0;
675 if(!Pen || !(Image = Pen->
Image))
693 if(fabs(dx) < fabs(dy))
712 xend = (
int)floor(x1 + 0.5f);
713 yend = y1 + Gradient * (xend - x1);
715 Gap = 1 - fpart(x1 + 0.5f);
717 iy1 = (
int)floor(yend);
721 PlotPixel(Image, Width, Height, ix1, iy1, (1 - fpart(yend)) * Gap, Color);
722 PlotPixel(Image, Width, Height, ix1, iy1 + 1, fpart(yend) * Gap, Color);
726 PlotPixel(Image, Width, Height, iy1, ix1, (1 - fpart(yend)) * Gap, Color);
727 PlotPixel(Image, Width, Height, iy1 + 1, ix1, fpart(yend) * Gap, Color);
730 xend = (int)floor(x2 + 0.5f);
731 yend = y2 + Gradient * (xend - x2);
732 Gap = fpart(x2 + 0.5f);
734 iy2 = (int)floor(yend);
738 PlotPixel(Image, Width, Height, ix2, iy2, (1 - fpart(yend)) * Gap, Color);
739 PlotPixel(Image, Width, Height, ix2, iy2 + 1, fpart(yend) * Gap, Color);
741 for(ix = ix1 + 1; ix < ix2; ix++)
744 PlotPixel(Image, Width, Height, ix, iy, 1 - fpart(y), Color);
745 PlotPixel(Image, Width, Height, ix, iy + 1, fpart(y), Color);
751 PlotPixel(Image, Width, Height, iy2, ix2, (1 - fpart(yend)) * Gap, Color);
752 PlotPixel(Image, Width, Height, iy2 + 1, ix2, fpart(yend) * Gap, Color);
754 for(ix = ix1 + 1; ix < ix2; ix++)
757 PlotPixel(Image, Width, Height, iy, ix, 1 - fpart(y), Color);
758 PlotPixel(Image, Width, Height, iy + 1, ix, fpart(y), Color);
776 if(!Pen || !Image || Width <= 0 || Height <= 0)
802 if(Pen && (File = Pen->
File))
809 fputs(
" setrgbcolor\n", File);
820 static int EpsDrawLine(
pen *Pen,
float x1,
float y1,
float x2,
float y2)
823 double xt1, yt1, xt2, yt2;
826 if(!Pen || !(File = Pen->
File))
843 fputs(
" m1\n", File);
854 static int EpsDrawQBezier(
pen *Pen,
float x1,
float y1,
855 float x2,
float y2,
float x3,
float y3)
858 double xt1, yt1, xt2, yt2, xt3, yt3;
861 if(!Pen || !(File = Pen->
File))
876 PenWriteDouble(File, (xt3 - xt1) + (2.0/3.0)*(xt2 - xt3), NumDigits);
878 PenWriteDouble(File, (yt3 - yt1) + (2.0/3.0)*(yt2 - yt3), NumDigits);
887 fputs(
" m2\n", File);
900 static int EpsDrawEllipse(
pen *Pen,
float x,
float y,
901 float rx,
float ry,
float Theta)
906 if(!Pen || !(File = Pen->
File))
921 fputs(
" m3\n", File);
933 int EpsOpen(
pen *Pen,
const char *FileName,
float Width,
float Height)
937 if(!(File = fopen(FileName,
"wb")))
939 ErrorMessage(
"Failed to open for writing \"%s\".\n", FileName);
946 fputs(
"%%!PS-Adobe-2.0\n%%%%BoundingBox: 0 0 ", File);
953 fputs(
"<< /PageSize [", File);
957 fputs(
"] >> setpagedevice\n", File);
958 fputs(
"systemdict /setdistillerparams known {\n"
959 "<< /AutoFilterGrayImages false /GrayImageFilter /FlateEncode "
960 "/AutoFilterColorImages false /ColorImageFilter /FlateEncode "
961 ">> setdistillerparams\n"
964 fputs(
"/bdef {bind def} bind def\n"
965 "/m1 {moveto rlineto stroke} bdef\n"
966 "/m2 {moveto rcurveto stroke} bdef\n"
967 "/m3 {/savematrix matrix currentmatrix def\n"
968 "translate rotate scale 0 0 1 0 360 arc\n"
969 "savematrix setmatrix stroke} bdef\n"
970 "0.2 setlinewidth\n", File);
998 if(!Pen || !(Pen->
File)
999 || fputs(
"showpage\n", Pen->
File) == EOF
1000 || ferror(Pen->
File)
1001 || fclose(Pen->
File))
1017 unsigned long Tuple, Plain[4];
1018 unsigned int Encoded[5];
1019 int i, k, LineCount, Padding;
1023 for(i = 0, LineCount = 0; i < NumBytes; i += 4)
1025 for(k = 0; k < 4; k++)
1026 Plain[k] = Data[i + k];
1028 Tuple = (Plain[0] << 24) | (Plain[1] << 16)
1029 | (Plain[2] << 8) | Plain[3];
1031 for(k = 4; k >= 0; k--)
1033 Encoded[k] = Tuple % 85;
1037 for(k = 0; k < 5; k++)
1038 fputc(33 + Encoded[k], File);
1041 if(++LineCount >= 15)
1045 if(fprintf(File,
"\n") < 0)
1053 for(k = 0; i + k < NumBytes; k++)
1054 Plain[k] = Data[i + k];
1056 for(Padding = 0; k < 4; k++, Padding++)
1059 Tuple = (Plain[0] << 24) | (Plain[1] << 16)
1060 | (Plain[2] << 8) | Plain[3];
1062 for(k = 4; k >= 0; k--)
1064 Encoded[k] = Tuple % 85;
1068 for(k = 0; k < 5 - Padding; k++)
1069 fputc(33 + Encoded[k], File);
1071 if(++LineCount >= 15
1072 && fprintf(File,
"\n") < 0)
1076 if(fprintf(File,
"~>\n") < 0 || ferror(File))
1101 const uint8_t *Image,
int Width,
int Height)
1104 if(!File || !Image || fprintf(File,
1106 "/DeviceGray setcolorspace\n"
1107 "0 %d translate %d %d scale\n"
1111 " /ImageMatrix [%d 0 0 -%d 0 0]\n"
1112 " /BitsPerComponent 8\n"
1114 " /DataSource currentfile /ASCII85Decode filter\n"
1115 " /Interpolate false\n"
1117 Height, Width, Height,
1118 Width, Height, Width, Height) < 0
1120 || fprintf(File,
"grestore\n") < 0)
1145 const uint8_t *Image,
int Width,
int Height)
1148 if(!File || !Image || fprintf(File,
1150 "/DeviceRGB setcolorspace\n"
1151 "0 %d translate %d %d scale\n"
1155 " /ImageMatrix [%d 0 0 -%d 0 0]\n"
1156 " /BitsPerComponent 8\n"
1157 " /Decode [0 1 0 1 0 1]\n"
1158 " /DataSource currentfile /ASCII85Decode filter\n"
1159 " /Interpolate false\n"
1161 Height, Width, Height,
1162 Width, Height, Width, Height) < 0
1164 || fprintf(File,
"grestore\n") < 0)
1177 static void WriteHexColor(FILE *File,
const float *Color)
1179 fprintf(File,
"#%02X%02X%02X",
1180 (
int)(255*Color[0] + 0.5f),
1181 (
int)(255*Color[1] + 0.5f),
1182 (
int)(255*Color[2] + 0.5f));
1192 static int SvgDrawLine(
pen *Pen,
float x1,
float y1,
float x2,
float y2)
1198 if(!Pen || !(File = Pen->
File))
1202 fputs(
"<line ", File);
1205 fprintf(File,
"class=\"%c\" ",
'a' + Pen->
ColorIndex);
1208 fputs(
"style=\"stroke:", File);
1209 WriteHexColor(File, Pen->
Color);
1215 fputs(
"x1=\"", File);
1217 fputs(
"\" y1=\"", File);
1222 fputs(
"\" x2=\"", File);
1224 fputs(
"\" y2=\"", File);
1226 fputs(
"\" />\n", File);
1237 static int SvgDrawQBezier(
pen *Pen,
1238 float x1,
float y1,
float x2,
float y2,
float x3,
float y3)
1241 double xt0, yt0, xt, yt;
1244 if(!Pen || !(File = Pen->
File))
1248 fputs(
"<path ", File);
1251 fprintf(File,
"class=\"%c\" ",
'a' + Pen->
ColorIndex);
1254 fputs(
"style=\"stroke:", File);
1255 WriteHexColor(File, Pen->
Color);
1256 fputs(
"; fill:none\" ", File);
1261 fputs(
"d=\"M", File);
1279 fputs(
"\" />\n", File);
1292 static int SvgDrawEllipse(
pen *Pen,
1293 float x,
float y,
float rx,
float ry,
float Theta)
1296 int NumDigits, IsCircle;
1298 if(!Pen || !(File = Pen->
File))
1303 IsCircle = (fabs(rx - ry) < 1e-2);
1306 fputs(
"<circle ", File);
1308 fputs(
"<ellipse ", File);
1311 fprintf(File,
"class=\"%c\" ",
'a' + Pen->
ColorIndex);
1314 fputs(
"style=\"stroke:", File);
1315 WriteHexColor(File, Pen->
Color);
1321 if(!IsCircle && fabs(Theta) >= 1e-2 && abs(Theta - 180) >= 1e-2)
1323 fputs(
"transform=\"rotate(", File);
1329 fputs(
")\" ", File);
1332 fputs(
"cx=\"", File);
1334 fputs(
"\" cy=\"", File);
1338 fputs(
"\" r=\"", File);
1341 fputs(
"\" rx=\"", File);
1343 fputs(
"\" ry=\"", File);
1347 fputs(
"\" />\n", File);
1359 int SvgOpen(
pen *Pen,
const char *FileName,
float Width,
float Height)
1364 if(!FileName || !(File = fopen(FileName,
"wb")))
1366 ErrorMessage(
"Failed to open for writing \"%s\".\n", FileName);
1374 fputs(
"<?xml version=\"1.0\" standalone=\"no\"?>\n"
1375 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n"
1376 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n", File);
1379 fputs(
"<svg width=\"", File);
1381 fputs(
"\" height=\"", File);
1383 fputs(
"\" version=\"1.1\"\n"
1384 " xmlns=\"http://www.w3.org/2000/svg\""
1385 " xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n", File);
1390 fputs(
"<defs>\n<style type=\"text/css\"><![CDATA[\n", File);
1394 fprintf(File,
".%c {stroke:",
'a' + i);
1395 WriteHexColor(File, Pen->
Palette[i]);
1396 fputs(
"; stroke-width:2; fill:none}\n", File);
1399 fputs(
"]]></style>\n</defs>\n", File);
1428 if(!Pen || !(Pen->
File)
1429 || fputs(
"</svg>\n", Pen->
File) == EOF
1430 || ferror(Pen->
File)
1431 || fclose(Pen->
File))