/**************************
* Headers
**************************/
#include <iostream>
#include <iomanip>
#include <sstream>
#include <fstream>
#include <complex>
#include <cmath>
#include "pdf.h"
/**************************
* Using Declarations
**************************/
using std::ostringstream;
using std::ifstream;
using std::complex;
using std::cout;
using std::endl;
using std::ios;
/**************************
* Local Functions
**************************/
// ---------------------------------------------------
// Multiply degrees by (2 * pi / 360.0) to
// obtain radians
// ---------------------------------------------------
static double degreesToRadians(int degrees)
{
return((3.14159 / 180.0) * degrees);
}
// ---------------------------------------------------
// Read 'fileName' and populate 'lines' with its
// contents (on success, return true). On error,
// populate 'errMsg' and return false.
// ---------------------------------------------------
static bool getLines(
const string &fileName,
vector<string> &lines,
string &errMsg
)
{
ifstream in;
in.open(fileName.c_str(), ios::binary);
if(!in)
{
errMsg = "Could not open: [" + fileName + "]";
return(false);
}
string line = "";
for(;;)
{
char c = (char)in.get();
if(in.eof())
{
if(line != "")
lines.push_back(line);
break;
}
line += c;
if(c == '\n')
{
lines.push_back(line);
line = "";
}
}
in.close();
return(true);
}
// ---------------------------------------------------
// Draw 'theText' at: [x, y] (using the specified
// font and font size) with a box around it
// ---------------------------------------------------
static void drawBoundedText(
const string &theText,
int x,
int y,
PDF::Font theFont,
int fontSize,
PDF &p
)
{
p.setFont(theFont, fontSize);
p.showTextXY(theText, x, y);
int width = PDF::stringWidth(
theFont, fontSize, theText
);
int offset = (int)(0.4 * fontSize + 0.5);
p.drawRect(x, y - offset, width, fontSize + offset);
}
// ---------------------------------------------------
// Demonstrate:
//
// - text wrapping
// - drawing and filling of circles and ellipses
// - drawing and filling of rectangles and polygons
// - drawing lines, using different line widths
// - use of images
// ---------------------------------------------------
static void demoOne(PDF &p)
{
p.setFont(PDF::HELVETICA, 12);
string s = " \t\t fee \r\nxxxxxxxxxxxxx\r\n\"fi\"fo fum";
s += " a aa aaa aaaa bbb bb b c cc ccc dddd eeeee ";
s += " foo bar baz foo bar baz ";
s += " mairzy doats and doazy doats and little lambsey divey";
s += " a kiddley divey too, wouldn't you? ";
s += " a b c d e f g h i jj kkk llll mmmmmm nnnnnnn oooooooooooo ";
s += "----------------------- -------------------------- ";
s += "$$$ $$$$$$$$$$$$$$ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ ";
s += "******************** ************************ ***** ";
vector<string> sv = p.wrapText(s, 100, true);
for(int i = 0, n = sv.size(); i < n; i ++)
{
// cout << "sv[" << i << "][" << sv[i] << "]\n";
p.showTextXY(sv[i], 80, 745 - 20 * i);
}
p.drawLine(80, 760, 80, 300);
p.drawLine(180, 760, 180, 300);
// cout << endl;
p.drawEllipse(400, 550, 150, 75);
p.setFillColor(255, 255, 0);
p.fillEllipse(400, 550, 40, 65);
p.drawEllipse(400, 550, 40, 65);
for(int i = 0; i < 12; i ++)
{
unsigned char value = (unsigned char)(20 * i);
p.setFillColor(value, value, value);
p.fillCircle(480, 310 + 10 * i, 2 * i);
p.drawCircle(480, 310 + 10 * i, 3 * i);
}
p.setLineColor(255, 0, 0);
p.setFillColor(0, 0, 255);
for(int i = 0; i < PDF::N_FONTS; i ++)
{
PDF::Font theFont = (PDF::Font)(i + 1);
int fontSize = 9;
int x = 10;
int y = 36 + (2 * fontSize) * i;
string s =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
"!@#$%^&*()_-=+[]{};:<>,./?";
drawBoundedText(s, x, y, theFont, fontSize, p);
}
p.fillRect(300, 700, 40, 40);
p.drawRect(400, 700, 40, 40);
p.newPage();
p.setLineColor(255, 0, 0);
for(int i = 0; i < PDF::N_FONTS; i ++)
{
p.setFont((PDF::Font)(i + 1), 20);
p.showTextXY(PDF::FONTS[i], 100, 100 + 40 * i);
}
p.newPage();
p.setLineColor(255, 0, 0);
for(int i = 0; i < 20; i ++)
{
p.drawLine(0, 0, 30 * (1 + i), 500 - 15 * i);
p.setLineWidth(i/2 + 1);
}
vector<XY> points;
points.push_back(XY(300, 500));
points.push_back(XY(325, 550));
points.push_back(XY(350, 480));
points.push_back(XY(375, 570));
points.push_back(XY(400, 460));
points.push_back(XY(425, 590));
points.push_back(XY(450, 450));
p.setLineColor(0, 255, 0);
p.drawLine(points);
points.clear();
points.push_back(XY(100, 540));
points.push_back(XY(150, 700));
points.push_back(XY( 80, 700));
p.setFillColor(200, 200, 200);
p.fillPolygon(points);
p.setLineColor(0, 0, 255);
p.drawPolygon(points);
p.newPage();
// Make an image
ImageRow row1;
ImageRow row2;
row1.push_back(RGB(255, 255, 0));
row1.push_back(RGB(255, 0, 255));
row1.push_back(RGB( 0, 255, 0));
row2.push_back(RGB( 0, 0, 255));
row2.push_back(RGB(255, 0, 0));
row2.push_back(RGB( 0, 0, 255));
Image anImage;
anImage.push_back(row1);
anImage.push_back(row2);
ImageInfo info = p.processImage(anImage);
double scale = 50.0;
for(int i = 0; i < 10; i ++)
{
int xValue = 120 + 30 * i;
int yValue = 220 + 40 * i;
p.showImage(info, xValue, yValue, scale);
p.drawRect(
xValue,
yValue,
(int)(scale * info.mWidth + 0.5),
(int)(scale * info.mHeight + 0.5)
);
}
}
// ---------------------------------------------------
// Demonstrate:
//
// - the use of 'drawLine' and trigonometry
// to create a geometric line drawing
// ---------------------------------------------------
static void demoTwo(PDF &p)
{
int xc = p.getWidth() / 2;
int yc = p.getHeight() / 2;
int smaller = (xc < yc ? xc : yc);
int radius = (int)(.9 * smaller);
int step = 15;
for(int i = 0; i < 360; i += step)
{
double angle = degreesToRadians(i);
int x0 = xc + (int)(radius * cos(angle) + 0.5);
int y0 = yc + (int)(radius * sin(angle) + 0.5);
for(int j = 0; j < 360; j += step)
{
if(j != i)
{
double theAngle = degreesToRadians(j);
int x1 = xc + (int)(radius * cos(theAngle) + 0.5);
int y1 = yc + (int)(radius * sin(theAngle) + 0.5);
p.drawLine(x0, y0, x1, y1);
}
}
}
}
// ---------------------------------------------------
// Demonstrate:
//
// - ability to embed program code (this function,
// 'demoThree' itself) in the pdf
//
// - use of images to create and store a
// generated fractal image
//
// Note: The comments before and after the
// 'demoThree' function that look like this:
//
// // begin: demoThree
// // end: demoThree
//
// are markers in the source so that the
// code for the 'demoThree' function can
// be extracted and written to the pdf file
// file and that process will fail if those
// comments are altered/removed
//
// ---------------------------------------------------
// begin: demoThree
static void demoThree(PDF &p)
{
// Create an image, 500 pixels square
int width = 500;
int height = 500;
Image anImage;
RGB theColor(0, 0, 0);
for(int i = 0; i < height; i ++)
{
ImageRow theRow;
for(int j = 0; j < width; j ++)
theRow.push_back(theColor);
anImage.push_back(theRow);
}
double yStart = -2.0;
double yStop = 2.0;
double yStep = (yStop - yStart) / (height - 1);
double xStart = -2.0;
double xStop = 2.0;
double xStep = (xStop - xStart) / (width - 1);
int maxIterations = 25;
double maxDistance = 1000.0;
typedef complex<double> Complex;
int iValue = 0;
for(double y = yStart; y <= yStop; y += yStep)
{
int jValue = 0;
for(double x = xStart; x <= xStop; x += xStep)
{
Complex z(0.0, 0.0);
Complex c(x, y);
int iterations = 0;
while(
iterations < maxIterations &&
sqrt(z.real() * z.real() + z.imag() * z.imag()) < maxDistance
)
{
z = z * z + c;
iterations ++;
}
double v1 = (double)iterations / maxIterations;
double v2 = sqrt(v1);
double v3 = sqrt(v2);
v1 *= 255.0;
v2 *= 255.0;
v3 *= 255.0;
unsigned char red = (unsigned char)(v1 + 0.5);
unsigned char green = (unsigned char)(v2 + 0.5);
unsigned char blue = (unsigned char)(v3 + 0.5);
RGB theColor(red, green, blue);
anImage[iValue][jValue] = theColor;
jValue++;
}
iValue++;
}
// Place the image, centered
ImageInfo info = p.processImage(anImage);
int xValue = (p.getWidth() / 2) - (width / 2);
int yValue = (p.getHeight() / 2) - (height / 2);
p.showImage(info, xValue, yValue, 1.0);
p.newPage();
string errMsg;
vector<string> lines;
if(!getLines(__FILE__, lines, errMsg))
{
cout << errMsg;
}
else
{
static const int FONTSIZE = 8;
static const int MARGIN = 36;
static const int YSTART = 750;
int y = YSTART;
bool showLine = false;
// Avoid false positive by buidling our
// markerBegin and markerEnd strings up dynamically
string tag = "demoThree";
string markerBegin = "// begin: " + tag;
string markerEnd = "// end: " + tag;
bool needSetFont = true;
for(int i = 0, n = lines.size(); i < n; i ++)
{
if(!showLine)
{
if(lines[i].find(markerBegin) != string::npos)
showLine = true;
}
else
{
if(lines[i].find(markerEnd) != string::npos)
showLine = false;
if(showLine)
{
if(needSetFont)
{
p.setFont(PDF::COURIER, FONTSIZE);
needSetFont = false;
}
p.showTextXY(lines[i], MARGIN, y);
y -= FONTSIZE;
if(y <= MARGIN)
{
p.newPage();
needSetFont = true;
y = YSTART;
}
}
}
}
}
}
// end: demoThree
/**************************
* Main
**************************/
int main()
{
typedef void (*DemoFunction)(PDF &);
DemoFunction functions[] =
{
demoOne, demoTwo, demoThree
};
int n = sizeof(functions) / sizeof(functions[0]);
for(int i = 0; i < n; i ++)
{
ostringstream out;
out << "example-" << i << ".pdf";
string fileName = out.str();
cout << "-----------------------------------------" << "\n";
cout << "Creating File: [" << fileName << "]" << "\n";
cout << "-----------------------------------------" << "\n";
PDF pdf;
functions[i](pdf);
string errMsg;
if(!pdf.writeToFile(fileName, errMsg))
{
cout << errMsg << endl;
}
else
{
cout << "(File Successfully Written)" << endl;
}
cout << endl;
}
return(0);
}