|
Table of Contents |
| file | contents | use with C++ | use with C |
|---|---|---|---|
| svf_outb.cpp | output binary SVF | * | * |
| svf_outc.cpp | C API wrapper around C++ API | * | |
| svf_outg.cpp | general SVF support | * | * |
| svf_outx.cpp | output XML SVF | * | * |
| svfout.hpp | C++ API definition | * | * |
| svfout.h | C API definition | * | |
| svfcom.h | command and enum definitions | * | * |
To use the C++ API, include svfout.hpp. To use the C API, include svfout.h.
If you're compiling on a machine with big-endian architecture (such as
a Mac using a 680x0 chip, a Sun, etc.), you should define BIGENDIAN
for svfout.cpp. If your machine is little-endian (such as a Pentium),
you should define LITTLEENDIAN.
By default, strings passed to the C and C++ APIs are UTF-8 encoded Unicode
(see strings for more information),
thus simple character arrays that just consist of lower ASCII are valid parameters.
If you wish to specify all strings as arrays of 16-bit shorts,
define SVF_UTF16 for all the SVF project files and all files
which include the SVF header files.
The following C++ code creates an SVF file named "myfile.svf" and writes a single line from (10,20) to (200,150).
#include "svfout.hpp"
cFileOutput file;
if (!file.Open("myfile.svf", FALSE))
return;
cSVFWrite *write = cSVFWrite::CreateBinaryOutput(&file);
write->HandleStart();
write->HandleMoveToI(10,20);
write->HandleLineToI(200,150);
write->HandleEnd();
delete write;
The following C example does the same thing. The C API hides the use
of cFileOutput and HandleStart but at the
expense of not being able to do generic output
or reuse the SVF class object.
#include "svfout.h"
sSVFObject *svf = SVFOpen("myfile.svf");
if (svf == NULL)
return;
SVFOutputMoveTo(svf,10,20);
SVFOutputLineTo(svf,200,150);
SVFClose(svf);
To output XML from C++, pass TRUE to cFileOutput::Open
and call cSVFWrite::CreateXMLOutput. To output XML from C, call
SVFOpenXML instead of SVFOpen.
Note that these examples are based on default values for extents, color, layer, etc. See the defaults table for more specifics. The most important default to override is the extents of the image. This describes the minimum and maximum coordinate values contained in the SVF file. If the SVF image contains a line from (0,0) to (1000,1000), the extents should be at least that big.
write->HandleStart(); write->HandleExtentsI(0,0, 1000,1000); write->HandleMoveToI(0,0); write->HandleLineToI(1000,1000); write->HandleEnd();
The 1.1 API was only available in C. With one change, code written to
the old API should continue to work as is. Previously SVFOpen()
returned a FILE* but now it returns an sSVFObject*.
Code that looked like the following...
FILE *fp = SVFOpen("myfile.svf");
if (fp == NULL)
return;
SVFOutputMoveTo(fp,10,20);
SVFOutputLineTo(fp,200,150);
SVFClose(fp);
...will work with the new API simply by changing FILE to
sSVFObject as in the following example:
sSVFObject *fp = SVFOpen("myfile.svf");
if (fp == NULL)
return;
SVFOutputMoveTo(fp,10,20);
SVFOutputLineTo(fp,200,150);
SVFClose(fp);
SVF supports the Unicode character set which allows for most characters from most languages in a platform independent manner (see strings in the SVF specification for more information).
The C/C++ API allows the programmer to pass strings using either the UTF-8 or
UTF-16 encoding of Unicode. By default, strings are defined as char*
and interpreted as UTF-8. This allows you to pass lower ASCII characters
without modification yet any Unicode character can still be passed. If you
wish to use 2 byte characters, define SVF_UTF16 for your project.
Then strings are defined as unsigned short* and interpreted as UTF-16.
This allows you to pass 2 byte Unicode characters to the API yet it still allows
Unicode values that can't fit in 2 bytes. Note that all strings passed to the API
must be null terminated.
To allow the programmer to work with the UTF-8 and UTF-16 encodings of Unicode
with minimal effort, several API functions are provided for converting between
various encodings. UCS-4 is the 4 byte version of Unicode and can be stored
in a long in C. UCS-2 is the 2 byte version of Unicode and can be
stored in a short in C. cGenericOutput::UCS4toUTF8
converts a UCS-2 or UCS-4 character into UTF-8. cGenericOutput::UTF16toUCS4
converts a UTF-16 string into UCS-4. cGenericOutput::IsValidUTF8
can be used to make sure a string is valid UTF-8.
// default string method - strings are UTF-8
write->HandleName("This is a normal ASCII string.");
// build up a UTF-8 string out of Unicode characters
char utf8[20];
int len = cGenericOutput::UCS4toUTF8(0xa9, utf8); // copyright symbol
len += cGenericOutput::UCS4toUTF8(0x2264, &utf8[len]); // <= math symbol
utf8[len] = 0;
write->HandleTextI(0,utf8);
In the following example, SVF_UTF16 is defined for the project.
In C, L can be used as a string prefix to indicate that characters
in the string are 2 byte values.
// all strings are UTF-16
write->HandleName(L"This is a normal Unicode string.");
unsigned short utf16[] = { 0xa9, 0x2264, 0 };
write->HandleTextI(0,utf16);
Most commands can store their parameters in 1, 2, 4 or 8 bytes of precision
as appropriate to make the file more compact. Coordinates and distances
can store their values as 1, 2 or 4 byte integers or 8 byte floating point
values. These functions use a postfix of I for integers and D for double
floating point values (e.g. HandlePointI and HandlePointD).
Generally the integer functions can automatically choose the minimum precision
necessary for storage with the exception of angles and polylines. For
these functions you can pass the desired precision, which defaults to 2
byte integers.
// automatically writes 1 byte integers write->HandlePointI(100,100); // automatically writes 2 byte integers write->HandlePointI(1000,1000); // automatically writes 4 byte integers write->HandlePointI(100000,100000); // writes 8 byte floating point write->HandlePointD(3.14,1.414); // writes 2 byte integers write->HandleArcI(7000, 0.707, 3.142); // writes 4 byte integers write->HandleArcI(7000, 0.707, 3.142, 4); // write a 2 point polyline using 2 byte integers write->HandlePolylineStart(2); write->HandlePolyPointI(2000,2200); write->HandlePolyPointI(3000,3200); // write a 2 point polyline using 8 byte floating point write->HandlePolylineStart(2,8); write->HandlePolyPointD(4.23,3.21); write->HandlePolyPointD(7.13,0.9);
Graphic objects in SVF are drawn based on the current state of such properties as location, color, layer, etc. These values start with a default value. Then various commands can be used to change these values.
write->HandleStart(); write->HandleMoveToI(50,50); // circle of radius 10 centered at current point (50,50) // using current color, layer, etc. write->HandleCircleI(10); // all subsequent objects drawn in red until the next color change write->HandleSetColor(SVFC_Red); // circle centered at current point (50,50) in red write->HandleCircleI(20); write->HandleEnd();
SVF is designed so it can be streamed well, that is, the image can be displayed immediately before the whole file has been downloaded. A viewer doesn't need to make a pass through the file first to find information necessary for displaying. Thus the header portion of an SVF file can contain extents, layers, colors, fonts, data types, and other information. This information should be written out before any graphic objects are written.
By default, SVF references a 256 color table of RGB values by index (see
colors for information on this table).
The enumerated type eSVFDefaultColors in svfcom.h
provides some default color values. Or, if you know the RGB value of the
color, you can use cSVFWrite::GetClosestColor to find the
closest match in the default color table. Colors are specified as RGB
(red/green/blue) values which range from 0, black, to 255, pure color.
write->HandleSetColor(SVFC_Black); write->HandleSetColor(SVFC_White); write->HandleSetColor(SVFC_Red); svfvalue mycolor = cSVFWrite::GetClosestColor(30,192,115); write->HandleSetColor(mycolor);
Alternately, you can build your own color table for optimizing the colors
on a system which uses a palette (such as 256 color graphics card).
The number passed to HandleBackground, HandleTransparent
or HandleSetColor would then be an index into your custom color table.
write->HandleColorTable(256); // create a palette that just consists of shades of green for (int i=0; i<256; i++) write->HandleColorEntry(0,i,0); // have the image use a black (entry 0) background write->HandleBackground(0);
A third option is to reference colors by RGB value. Each value ranges from 0 (dark) to 255 (bright).
write->HandleSetColor(255,0,0); // pure red write->HandleSetColor(50,50,50); // dark gray write->HandleSetColor(255,255,255); // white
The cSVFWrite derived classes write to a cGenericOutput
object which handles architecture specific output and Unicode encoding issues.
Derived from cGenericOutput is cFileOutput which
can write to a file. If you need to send output somewhere else, a memory
buffer, a network socket, etc., derive from cGenericOutput and
override the two protected write functions. Then pass this
object to one of the create SVF functions in cSVFWrite.
class cMyOutput : public cGenericOutput
{
protected:
virtual bool write(char v);
virtual bool write(void *v, int length);
};