tioga 1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/Tioga_README +372 -0
- data/lgpl.txt +504 -0
- data/split/Dtable/defs.h +33 -0
- data/split/Dtable/dtable.c +1928 -0
- data/split/Dtable/dtable_intern.h +144 -0
- data/split/Dtable/dvector.h +61 -0
- data/split/Dtable/extconf.rb +4 -0
- data/split/Dtable/include/dtable.h +35 -0
- data/split/Dtable/lib/Dtable_extras.rb +90 -0
- data/split/Dtable/namespace.h +47 -0
- data/split/Dtable/safe_double.h +104 -0
- data/split/Dtable/symbols.c +92 -0
- data/split/Dtable/symbols.h +52 -0
- data/split/Dvector/defs.h +33 -0
- data/split/Dvector/dvector.c +5486 -0
- data/split/Dvector/dvector_intern.h +142 -0
- data/split/Dvector/extconf.rb +4 -0
- data/split/Dvector/include/dvector.h +61 -0
- data/split/Dvector/lib/Dvector_extras.rb +328 -0
- data/split/Dvector/lib/Numeric_extras.rb +134 -0
- data/split/Dvector/namespace.h +47 -0
- data/split/Dvector/safe_double.h +104 -0
- data/split/Dvector/symbols.c +92 -0
- data/split/Dvector/symbols.h +52 -0
- data/split/Flate/defs.h +33 -0
- data/split/Flate/extconf.rb +19 -0
- data/split/Flate/flate.c +156 -0
- data/split/Flate/flate_intern.h +97 -0
- data/split/Flate/include/flate.h +98 -0
- data/split/Flate/namespace.h +47 -0
- data/split/Flate/safe_double.h +104 -0
- data/split/Flate/symbols.c +92 -0
- data/split/Flate/symbols.h +52 -0
- data/split/Function/defs.h +33 -0
- data/split/Function/dvector.h +61 -0
- data/split/Function/extconf.rb +4 -0
- data/split/Function/function.c +988 -0
- data/split/Function/joint_qsort.c +258 -0
- data/split/Function/lib/Function_extras.rb +44 -0
- data/split/Function/namespace.h +47 -0
- data/split/Function/safe_double.h +104 -0
- data/split/Function/symbols.c +92 -0
- data/split/Function/symbols.h +52 -0
- data/split/Tioga/axes.c +774 -0
- data/split/Tioga/defs.h +33 -0
- data/split/Tioga/dtable.h +35 -0
- data/split/Tioga/dvector.h +61 -0
- data/split/Tioga/extconf.rb +4 -0
- data/split/Tioga/figures.c +672 -0
- data/split/Tioga/figures.h +855 -0
- data/split/Tioga/flate.h +98 -0
- data/split/Tioga/init.c +524 -0
- data/split/Tioga/lib/Arcs_and_Circles.rb +64 -0
- data/split/Tioga/lib/ColorConstants.rb +274 -0
- data/split/Tioga/lib/Colorbars.rb +10 -0
- data/split/Tioga/lib/Colormaps.rb +105 -0
- data/split/Tioga/lib/Coordinate_Conversions.rb +194 -0
- data/split/Tioga/lib/Creating_Paths.rb +94 -0
- data/split/Tioga/lib/Doc.rb +91 -0
- data/split/Tioga/lib/Executive.rb +515 -0
- data/split/Tioga/lib/FigMkr.rb +2224 -0
- data/split/Tioga/lib/FigureConstants.rb +125 -0
- data/split/Tioga/lib/Figures_and_Plots.rb +268 -0
- data/split/Tioga/lib/Images.rb +278 -0
- data/split/Tioga/lib/Legends.rb +190 -0
- data/split/Tioga/lib/MarkerConstants.rb +122 -0
- data/split/Tioga/lib/Markers.rb +129 -0
- data/split/Tioga/lib/Page_Frame_Bounds.rb +567 -0
- data/split/Tioga/lib/Rectangles.rb +94 -0
- data/split/Tioga/lib/Shading.rb +100 -0
- data/split/Tioga/lib/Special_Paths.rb +307 -0
- data/split/Tioga/lib/Strokes.rb +129 -0
- data/split/Tioga/lib/TeX_Text.rb +454 -0
- data/split/Tioga/lib/TexPreamble.rb +358 -0
- data/split/Tioga/lib/Titles_and_Labels.rb +306 -0
- data/split/Tioga/lib/Transparency.rb +89 -0
- data/split/Tioga/lib/Using_Paths.rb +164 -0
- data/split/Tioga/lib/Utils.rb +74 -0
- data/split/Tioga/lib/X_and_Y_Axes.rb +749 -0
- data/split/Tioga/lib/irb_tioga.rb +122 -0
- data/split/Tioga/lib/tioga.rb +1 -0
- data/split/Tioga/lib/tioga_ui.rb +5 -0
- data/split/Tioga/lib/tioga_ui_cmds.rb +793 -0
- data/split/Tioga/makers.c +989 -0
- data/split/Tioga/mk_tioga_sty.rb +53 -0
- data/split/Tioga/namespace.h +47 -0
- data/split/Tioga/pdf_font_dicts.c +18253 -0
- data/split/Tioga/pdfcolor.c +486 -0
- data/split/Tioga/pdfcoords.c +505 -0
- data/split/Tioga/pdffile.c +342 -0
- data/split/Tioga/pdfimage.c +536 -0
- data/split/Tioga/pdfpath.c +914 -0
- data/split/Tioga/pdfs.h +229 -0
- data/split/Tioga/pdftext.c +443 -0
- data/split/Tioga/safe_double.h +104 -0
- data/split/Tioga/symbols.c +92 -0
- data/split/Tioga/symbols.h +52 -0
- data/split/Tioga/texout.c +380 -0
- data/split/defs.h +33 -0
- data/split/extconf.rb +107 -0
- data/split/mkmf2.rb +1612 -0
- data/split/namespace.h +47 -0
- data/split/safe_double.h +104 -0
- data/split/scripts/tioga +4 -0
- data/split/symbols.c +92 -0
- data/split/symbols.h +52 -0
- data/tests/dtable_test.data +6 -0
- data/tests/dvector_read_test.data +1 -0
- data/tests/dvector_test.data +101 -0
- data/tests/tc_Dtable.rb +221 -0
- data/tests/tc_Dvector.rb +791 -0
- data/tests/tc_FMkr.rb +162 -0
- data/tests/tc_Flate.rb +45 -0
- data/tests/tc_Function.rb +111 -0
- data/tests/ts_Tioga.rb +38 -0
- metadata +163 -0
@@ -0,0 +1,342 @@
|
|
1
|
+
/* pdffile.c */
|
2
|
+
/*
|
3
|
+
Copyright (C) 2005 Bill Paxton
|
4
|
+
|
5
|
+
This file is part of Tioga.
|
6
|
+
|
7
|
+
Tioga is free software; you can redistribute it and/or modify
|
8
|
+
it under the terms of the GNU General Library Public License as published
|
9
|
+
by the Free Software Foundation; either version 2 of the License, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
Tioga is distributed in the hope that it will be useful,
|
13
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
GNU Library General Public License for more details.
|
16
|
+
|
17
|
+
You should have received a copy of the GNU Library General Public License
|
18
|
+
along with Tioga; if not, write to the Free Software
|
19
|
+
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
20
|
+
*/
|
21
|
+
|
22
|
+
#include <time.h>
|
23
|
+
#include "figures.h"
|
24
|
+
#include "pdfs.h"
|
25
|
+
|
26
|
+
#define FLATE_ENCODE 1
|
27
|
+
|
28
|
+
#define Get_pdf_xoffset() 5.0
|
29
|
+
#define Get_pdf_yoffset() 5.0
|
30
|
+
|
31
|
+
char *predefined_Fonts[] = { /* must match the font numbers in FigureConstants.rb */
|
32
|
+
NULL,
|
33
|
+
"Times-Roman",
|
34
|
+
"Times-Italic", // 2
|
35
|
+
"Times-Bold",
|
36
|
+
"Times-BoldItalic",
|
37
|
+
"Helvetica",
|
38
|
+
"Helvetica-Oblique", // 6
|
39
|
+
"Helvetica-Bold",
|
40
|
+
"Helvetica-BoldOblique",
|
41
|
+
"Courier",
|
42
|
+
"Courier-Oblique", // 10
|
43
|
+
"Courier-Bold",
|
44
|
+
"Courier-BoldOblique",
|
45
|
+
"Symbol",
|
46
|
+
"ZapfDingbats" // 14
|
47
|
+
};
|
48
|
+
int num_predefined_fonts = 14;
|
49
|
+
int num_pdf_standard_fonts = 14;
|
50
|
+
|
51
|
+
long int *obj_offsets, capacity_obj_offsets, stream_start, stream_end, length_offset, xref_offset;
|
52
|
+
int num_objects, next_available_object_number, next_available_gs_number, next_available_xo_number;
|
53
|
+
int next_available_shade_number, next_available_font_number;
|
54
|
+
Stroke_Opacity_State *stroke_opacities = NULL;
|
55
|
+
Fill_Opacity_State *fill_opacities = NULL;
|
56
|
+
XObject_Info *xobj_list = NULL;
|
57
|
+
Function_Info *functions_list;
|
58
|
+
Shading_Info *shades_list = NULL;
|
59
|
+
Font_Dictionary *font_dictionaries = NULL;
|
60
|
+
Old_Font_Dictionary *old_font_dictionaries = NULL;
|
61
|
+
FILE *OF = NULL; // for the PDF file
|
62
|
+
FILE *TF = NULL; // for the temp file
|
63
|
+
|
64
|
+
/* PDF File Management */
|
65
|
+
|
66
|
+
void Free_XObjects(void)
|
67
|
+
{
|
68
|
+
XObject_Info *xo;
|
69
|
+
while (xobj_list != NULL) {
|
70
|
+
xo = xobj_list;
|
71
|
+
xobj_list = xo->next;
|
72
|
+
switch (xo->xobj_subtype) {
|
73
|
+
case JPG_SUBTYPE: Free_JPG((JPG_Info *)xo); break;
|
74
|
+
case SAMPLED_SUBTYPE: Free_Sampled((Sampled_Info *)xo); break;
|
75
|
+
default: rb_raise(rb_eArgError, "Invalid XObject subtype (%i)", xo->xobj_subtype);
|
76
|
+
}
|
77
|
+
free(xo);
|
78
|
+
}
|
79
|
+
}
|
80
|
+
|
81
|
+
void Init_pdf(void)
|
82
|
+
{
|
83
|
+
int i;
|
84
|
+
writing_file = false;
|
85
|
+
capacity_obj_offsets = 1000;
|
86
|
+
num_objects = 0;
|
87
|
+
obj_offsets = ALLOC_N(long int, capacity_obj_offsets);
|
88
|
+
for (i=0; i < capacity_obj_offsets; i++) obj_offsets[i] = 0;
|
89
|
+
}
|
90
|
+
|
91
|
+
void Record_Object_Offset(int obj_number)
|
92
|
+
{
|
93
|
+
long int offset = ftell(OF);
|
94
|
+
if (obj_number >= capacity_obj_offsets) {
|
95
|
+
int size_increment = 50, i;
|
96
|
+
REALLOC_N(obj_offsets, long int, obj_number + size_increment);
|
97
|
+
capacity_obj_offsets = obj_number + size_increment;
|
98
|
+
for (i=num_objects; i < capacity_obj_offsets; i++) obj_offsets[i] = 0;
|
99
|
+
}
|
100
|
+
obj_offsets[obj_number] = offset;
|
101
|
+
if (obj_number >= num_objects) num_objects = obj_number + 1;
|
102
|
+
}
|
103
|
+
|
104
|
+
static void Write_XObjects(void)
|
105
|
+
{
|
106
|
+
XObject_Info *xo;
|
107
|
+
for (xo = xobj_list; xo != NULL; xo = xo->next) {
|
108
|
+
Record_Object_Offset(xo->obj_num);
|
109
|
+
fprintf(OF, "%i 0 obj << /Type /XObject ", xo->obj_num);
|
110
|
+
switch (xo->xobj_subtype) {
|
111
|
+
case JPG_SUBTYPE: Write_JPG((JPG_Info *)xo); break;
|
112
|
+
case SAMPLED_SUBTYPE: Write_Sampled((Sampled_Info *)xo); break;
|
113
|
+
default: rb_raise(rb_eArgError, "Invalid XObject subtype (%i)", xo->xobj_subtype);
|
114
|
+
}
|
115
|
+
fprintf(OF, ">> endobj\n");
|
116
|
+
}
|
117
|
+
}
|
118
|
+
|
119
|
+
#define INFO_OBJ 1
|
120
|
+
#define PAGES_OBJ 2
|
121
|
+
#define STREAM_OBJ 3
|
122
|
+
#define PAGE_OBJ 4
|
123
|
+
#define CATALOG_OBJ 5
|
124
|
+
#define FIRST_OTHER_OBJ 6
|
125
|
+
|
126
|
+
static void Free_Records()
|
127
|
+
{
|
128
|
+
Free_Stroke_Opacities(); Free_Fill_Opacities(); Free_XObjects(); Free_Shadings(); Free_Functions();
|
129
|
+
}
|
130
|
+
|
131
|
+
static void Get_pdf_name(char *ofile, char *filename, int maxlen)
|
132
|
+
{
|
133
|
+
char *dot;
|
134
|
+
strncpy(ofile, filename, maxlen);
|
135
|
+
dot = strrchr(ofile,'.');
|
136
|
+
if (dot != NULL) dot[0] = '\0';
|
137
|
+
strcat(ofile, "_figure.pdf");
|
138
|
+
}
|
139
|
+
|
140
|
+
void Open_pdf(VALUE fmkr, char *filename, bool quiet_mode)
|
141
|
+
{
|
142
|
+
FM *p = Get_FM(fmkr);
|
143
|
+
int i;
|
144
|
+
if (writing_file) rb_raise(rb_eArgError, "Sorry: cannot start a new output file until finish current one.");
|
145
|
+
Clear_Fonts_In_Use_Flags();
|
146
|
+
Free_Records();
|
147
|
+
next_available_object_number = FIRST_OTHER_OBJ;
|
148
|
+
next_available_font_number = num_predefined_fonts + 1;
|
149
|
+
next_available_gs_number = 1;
|
150
|
+
next_available_xo_number = 1;
|
151
|
+
next_available_shade_number = 1;
|
152
|
+
writing_file = true;
|
153
|
+
time_t now = time(NULL);
|
154
|
+
char ofile[300], timestring[100];
|
155
|
+
Get_pdf_name(ofile, filename, 300);
|
156
|
+
if ((OF = fopen(ofile, "w")) == NULL)
|
157
|
+
rb_raise(rb_eArgError, "Sorry: can't open %s.\n", filename);
|
158
|
+
if ((TF = tmpfile()) == NULL)
|
159
|
+
rb_raise(rb_eArgError, "Sorry: can't create temp file for writing PDF file %s.\n", filename);
|
160
|
+
/* open PDF file and write header */
|
161
|
+
fprintf(OF, "%%PDF-1.4\n");
|
162
|
+
strcpy(timestring, ctime(&now));
|
163
|
+
i = strlen(timestring);
|
164
|
+
if (i > 0) timestring[i-1] = '\0';
|
165
|
+
Record_Object_Offset(INFO_OBJ);
|
166
|
+
fprintf(OF, "%i 0 obj <<\n/Creator (Tioga)\n/CreationDate (%s)\n>>\nendobj\n", INFO_OBJ, timestring);
|
167
|
+
Record_Object_Offset(PAGES_OBJ);
|
168
|
+
fprintf(OF, "%i 0 obj <<\n/Type /Pages\n/Kids [%i 0 R]\n/Count 1\n>> endobj\n", PAGES_OBJ, PAGE_OBJ);
|
169
|
+
Record_Object_Offset(STREAM_OBJ);
|
170
|
+
if (FLATE_ENCODE)
|
171
|
+
fprintf(OF, "%i 0 obj <<\t/Filter /FlateDecode /Length ", STREAM_OBJ);
|
172
|
+
else
|
173
|
+
fprintf(OF, "%i 0 obj <<\t/Length ", STREAM_OBJ);
|
174
|
+
length_offset = ftell(OF);
|
175
|
+
fprintf(OF, " \n>>\nstream\n");
|
176
|
+
stream_start = ftell(OF);
|
177
|
+
fprintf(TF, "%.2f 0 0 %.2f %.2f %.2f cm\n", 1.0/ENLARGE, 1.0/ENLARGE,
|
178
|
+
Get_pdf_xoffset(), Get_pdf_yoffset());
|
179
|
+
/* set stroke and fill colors to black */
|
180
|
+
have_current_point = constructing_path = false;
|
181
|
+
c_line_width_set(p, p->line_width);
|
182
|
+
c_line_cap_set(p, p->line_cap);
|
183
|
+
c_line_join_set(p, p->line_join);
|
184
|
+
c_miter_limit_set(p, p->miter_limit);
|
185
|
+
FM_line_type_set(fmkr, p->line_type);
|
186
|
+
FM_stroke_color_set(fmkr, p->stroke_color);
|
187
|
+
FM_fill_color_set(fmkr, p->fill_color);
|
188
|
+
// initialize clip region
|
189
|
+
bbox_llx = bbox_lly = 1e5;
|
190
|
+
bbox_urx = bbox_ury = -1e5;
|
191
|
+
}
|
192
|
+
|
193
|
+
void Start_Axis_Standard_State(FM *p, VALUE color, double line_width) {
|
194
|
+
fprintf(TF, "q 2 J [] 0 d\n");
|
195
|
+
c_line_width_set(p, line_width);
|
196
|
+
if (color != Qnil)
|
197
|
+
FM_stroke_color_set(p->fm, color);
|
198
|
+
else
|
199
|
+
fprintf(TF, "0 0 0 RG\n"); // black
|
200
|
+
/* 2 J sets the line cap style to square cap */
|
201
|
+
/* set stroke and fill colors to black. set line type to solid */
|
202
|
+
}
|
203
|
+
|
204
|
+
void End_Axis_Standard_State(void) { Write_grestore(); }
|
205
|
+
|
206
|
+
void Write_gsave(void)
|
207
|
+
{
|
208
|
+
fprintf(TF, "q\n");
|
209
|
+
}
|
210
|
+
|
211
|
+
void Write_grestore(void)
|
212
|
+
{
|
213
|
+
fprintf(TF, "Q\n");
|
214
|
+
}
|
215
|
+
|
216
|
+
void Print_Xref(long int offset) {
|
217
|
+
char line[80];
|
218
|
+
int i, len;
|
219
|
+
sprintf(line, "%li", offset);
|
220
|
+
len = strlen(line);
|
221
|
+
for (i=0; i < 10-len; i++) fputc('0', OF);
|
222
|
+
fprintf(OF, "%s 00000 n \n", line);
|
223
|
+
}
|
224
|
+
|
225
|
+
static void Write_Stream(void)
|
226
|
+
{
|
227
|
+
long int len = ftell(TF);
|
228
|
+
unsigned long int new_len = (len * 11) / 10 + 100;
|
229
|
+
unsigned char *buffer, *dest_buffer;
|
230
|
+
rewind(TF);
|
231
|
+
buffer = ALLOC_N(unsigned char, len+1);
|
232
|
+
dest_buffer = ALLOC_N(unsigned char, new_len+1);
|
233
|
+
fread(buffer, 1, len, TF);
|
234
|
+
fclose(TF);
|
235
|
+
if (FLATE_ENCODE) {
|
236
|
+
if (flate_compress(dest_buffer, &new_len, buffer, len) != FLATE_OK) {
|
237
|
+
free(buffer); free(dest_buffer);
|
238
|
+
rb_raise(rb_eArgError, "Error compressing PDF stream data");
|
239
|
+
}
|
240
|
+
fwrite(dest_buffer, 1, new_len, OF);
|
241
|
+
} else {
|
242
|
+
fwrite(buffer, 1, len, OF);
|
243
|
+
}
|
244
|
+
free(buffer); free(dest_buffer);
|
245
|
+
}
|
246
|
+
|
247
|
+
void Close_pdf(VALUE fmkr, bool quiet_mode)
|
248
|
+
{
|
249
|
+
FM *p = Get_FM(fmkr);
|
250
|
+
int i;
|
251
|
+
double llx, lly, urx, ury, xoff, yoff;
|
252
|
+
if (!writing_file) rb_raise(rb_eArgError, "Sorry: cannot End_Output if not writing file.");
|
253
|
+
writing_file = false;
|
254
|
+
if (constructing_path) rb_raise(rb_eArgError, "Sorry: must finish with current path before ending file");
|
255
|
+
Write_Stream();
|
256
|
+
stream_end = ftell(OF);
|
257
|
+
fprintf(OF, "endstream\nendobj\n");
|
258
|
+
Record_Object_Offset(PAGE_OBJ);
|
259
|
+
fprintf(OF, "%i 0 obj <<\n/Type /Page\n/Parent %i 0 R\n/MediaBox [ ", PAGE_OBJ, PAGES_OBJ);
|
260
|
+
if (bbox_llx < p->page_left) bbox_llx = p->page_left;
|
261
|
+
if (bbox_lly < p->page_bottom) bbox_lly = p->page_bottom;
|
262
|
+
if (bbox_urx > p->page_left + p->page_width) bbox_urx = p->page_left + p->page_width;
|
263
|
+
if (bbox_ury > p->page_bottom + p->page_height) bbox_ury = p->page_bottom + p->page_height;
|
264
|
+
//#define MARGIN 3
|
265
|
+
#define MARGIN 0
|
266
|
+
xoff = Get_pdf_xoffset();
|
267
|
+
yoff = Get_pdf_yoffset();
|
268
|
+
llx = bbox_llx / ENLARGE + xoff - MARGIN; // convert back to points
|
269
|
+
lly = bbox_lly / ENLARGE + yoff - MARGIN;
|
270
|
+
urx = bbox_urx / ENLARGE + xoff + MARGIN;
|
271
|
+
ury = bbox_ury / ENLARGE + yoff + MARGIN;
|
272
|
+
if (urx < llx || ury < lly) rb_raise(rb_eArgError, "Sorry: Empty plot!");
|
273
|
+
fprintf(OF, "%d %d %d %d", ROUND(llx), ROUND(lly), ROUND(urx), ROUND(ury));
|
274
|
+
fprintf(OF, " ]\n/Contents %i 0 R\n/Resources << /ProcSet [/PDF /Text /ImageB /ImageC /ImageI]\n", STREAM_OBJ);
|
275
|
+
if (Used_Any_Fonts()) {
|
276
|
+
Font_Dictionary *f;
|
277
|
+
fprintf(OF, " /Font <<\n ");
|
278
|
+
for (f = font_dictionaries; f != NULL; f = f->next) {
|
279
|
+
if (!f->in_use) continue;
|
280
|
+
fprintf(OF, " /F%i %i 0 R\n", f->font_num, f->obj_num);
|
281
|
+
}
|
282
|
+
fprintf(OF, " >>\n"); // end of /Font
|
283
|
+
}
|
284
|
+
if (fill_opacities != NULL || stroke_opacities != NULL) { // ExtGstate objects go here
|
285
|
+
Fill_Opacity_State *pf;
|
286
|
+
Stroke_Opacity_State *ps;
|
287
|
+
fprintf(OF, " /ExtGState <<\n");
|
288
|
+
for (ps = stroke_opacities; ps != NULL; ps = ps->next) {
|
289
|
+
fprintf(OF, " /GS%i %i 0 R\n", ps->gs_num, ps->obj_num);
|
290
|
+
}
|
291
|
+
for (pf = fill_opacities; pf != NULL; pf = pf->next) {
|
292
|
+
fprintf(OF, " /GS%i %i 0 R\n", pf->gs_num, pf->obj_num);
|
293
|
+
}
|
294
|
+
fprintf(OF, " >>\n"); // end of /ExtGState
|
295
|
+
}
|
296
|
+
if (xobj_list != NULL) { // Xobjects go here
|
297
|
+
XObject_Info *xo;
|
298
|
+
fprintf(OF, " /XObject <<\n");
|
299
|
+
for (xo = xobj_list; xo != NULL; xo = xo->next) {
|
300
|
+
fprintf(OF, " /XObj%i %i 0 R\n", xo->xo_num, xo->obj_num);
|
301
|
+
}
|
302
|
+
fprintf(OF, " >>\n"); // end of /XObject
|
303
|
+
}
|
304
|
+
if (shades_list != NULL) { // Shadings go here
|
305
|
+
Shading_Info *so;
|
306
|
+
fprintf(OF, " /Shading <<\n");
|
307
|
+
for (so = shades_list; so != NULL; so = so->next) {
|
308
|
+
fprintf(OF, " /Shade%i %i 0 R\n", so->shade_num, so->obj_num);
|
309
|
+
}
|
310
|
+
fprintf(OF, " >>\n"); // end of /Shading
|
311
|
+
}
|
312
|
+
fprintf(OF, " >>\n"); // end of /Resources
|
313
|
+
fprintf(OF, ">> endobj\n");
|
314
|
+
Record_Object_Offset(CATALOG_OBJ);
|
315
|
+
fprintf(OF, "%i 0 obj <<\n/Type /Catalog\n/Pages %i 0 R\n>> endobj\n", CATALOG_OBJ, PAGES_OBJ);
|
316
|
+
Write_Font_Dictionaries();
|
317
|
+
Write_Font_Descriptors();
|
318
|
+
Write_Font_Widths();
|
319
|
+
Write_Stroke_Opacity_Objects();
|
320
|
+
Write_Fill_Opacity_Objects();
|
321
|
+
Write_XObjects();
|
322
|
+
Write_Functions();
|
323
|
+
Write_Shadings();
|
324
|
+
xref_offset = ftell(OF);
|
325
|
+
fprintf(OF, "xref\n0 %i\n0000000000 65535 f \n", num_objects);
|
326
|
+
for (i = 1; i < num_objects; i++) Print_Xref(obj_offsets[i]); // NB: DONT USE OBJECT 0
|
327
|
+
fprintf(OF, "trailer\n<<\n/Size %i\n/Root %i 0 R\n/Info %i 0 R\n>>\nstartxref\n%li\n%%%%EOF\n",
|
328
|
+
num_objects, CATALOG_OBJ, INFO_OBJ, xref_offset);
|
329
|
+
fseek(OF, length_offset, SEEK_SET);
|
330
|
+
fprintf(OF, "%li", stream_end - stream_start);
|
331
|
+
fclose(OF);
|
332
|
+
Free_Records();
|
333
|
+
}
|
334
|
+
|
335
|
+
void Rename_pdf(char *oldname, char *newname)
|
336
|
+
{
|
337
|
+
char old_ofile[300], new_ofile[300];
|
338
|
+
Get_pdf_name(old_ofile, oldname, 300);
|
339
|
+
Get_pdf_name(new_ofile, newname, 300);
|
340
|
+
rename(old_ofile, new_ofile); // from stdio.h
|
341
|
+
}
|
342
|
+
|
@@ -0,0 +1,536 @@
|
|
1
|
+
/* pdfimage.c */
|
2
|
+
/*
|
3
|
+
Copyright (C) 2005 Bill Paxton
|
4
|
+
|
5
|
+
This file is part of Tioga.
|
6
|
+
|
7
|
+
Tioga is free software; you can redistribute it and/or modify
|
8
|
+
it under the terms of the GNU General Library Public License as published
|
9
|
+
by the Free Software Foundation; either version 2 of the License, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
Tioga is distributed in the hope that it will be useful,
|
13
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
GNU Library General Public License for more details.
|
16
|
+
|
17
|
+
You should have received a copy of the GNU Library General Public License
|
18
|
+
along with Tioga; if not, write to the Free Software
|
19
|
+
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
20
|
+
*/
|
21
|
+
|
22
|
+
#include "figures.h"
|
23
|
+
#include "pdfs.h"
|
24
|
+
|
25
|
+
/* Images
|
26
|
+
|
27
|
+
invoke image by "/Image_name Do" in the content stream
|
28
|
+
|
29
|
+
the resources dictionary must have image object names in XObject dictionary
|
30
|
+
/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]
|
31
|
+
/XObject <<
|
32
|
+
/Image_name 30 0 R
|
33
|
+
...
|
34
|
+
>>
|
35
|
+
|
36
|
+
30 0 obj <<
|
37
|
+
/Type /XObject
|
38
|
+
/Subtype /Image
|
39
|
+
/Width <integer> number of columns. required for all.
|
40
|
+
/Height <integer> number of rows. required for all.
|
41
|
+
/Length <integer> number of bytes in image data stream. required for all.
|
42
|
+
/Interpolate <boolean> optional for all.
|
43
|
+
/SMask <stream> optional for all.
|
44
|
+
...
|
45
|
+
>>
|
46
|
+
stream
|
47
|
+
...image data...
|
48
|
+
endstream
|
49
|
+
endobj
|
50
|
+
|
51
|
+
For JPEG2000 images:
|
52
|
+
/Filter /JPXDecode
|
53
|
+
/Mask <image_mask_name> for explicit masking. optional.
|
54
|
+
|
55
|
+
For JPEG images:
|
56
|
+
/Filter /DCTDecode
|
57
|
+
/ColorSpace <name or array>. required. /DeviceRGB ?
|
58
|
+
/BitsPerComponent 8
|
59
|
+
/Mask <image_mask_name> for explicit masking. optional.
|
60
|
+
|
61
|
+
For sampled images:
|
62
|
+
/Filter <name> whatever filter being used for the image data. optional.
|
63
|
+
/ColorSpace <name or array>. required.
|
64
|
+
/BitsPerComponent 8
|
65
|
+
/Mask <image_mask_name> for explicit masking. optional.
|
66
|
+
/Mask [min, max] for masking out specified sample values.
|
67
|
+
for example, you can use 0 to stand for "undefined", then setting /Mask [0 0] will cause all
|
68
|
+
0 valued samples to be masked out of the image.
|
69
|
+
|
70
|
+
For image masks:
|
71
|
+
/ImageMask true
|
72
|
+
/BitsPerComponent 1
|
73
|
+
/Decode [0 1] means sample values of 0 are included in the output, values of 1 are excluded
|
74
|
+
/Decode [1 0] means sample values of 1 are included in the output, values of 0 are excluded
|
75
|
+
|
76
|
+
*/
|
77
|
+
|
78
|
+
|
79
|
+
void Free_JPG(JPG_Info *xo)
|
80
|
+
{
|
81
|
+
if (xo->filename != NULL) free(xo->filename);
|
82
|
+
}
|
83
|
+
|
84
|
+
void Free_Sampled(Sampled_Info *xo)
|
85
|
+
{
|
86
|
+
if (xo->image_data != NULL) free(xo->image_data);
|
87
|
+
if (xo->lookup != NULL) free(xo->lookup);
|
88
|
+
}
|
89
|
+
|
90
|
+
static bool Is_monochrome(int obj_num)
|
91
|
+
{
|
92
|
+
XObject_Info *xo;
|
93
|
+
for (xo = xobj_list; xo != NULL; xo = xo->next) {
|
94
|
+
if (xo->xobj_subtype == SAMPLED_SUBTYPE && xo->obj_num == obj_num) {
|
95
|
+
Sampled_Info *p = (Sampled_Info *)xo;
|
96
|
+
return (p->image_type == MONO_IMAGE);
|
97
|
+
}
|
98
|
+
}
|
99
|
+
return false;
|
100
|
+
}
|
101
|
+
|
102
|
+
static void Write_Image_From_File(char *filename, int width, int height, char *out_info, int mask_obj_num)
|
103
|
+
{
|
104
|
+
FILE *jpg = fopen(filename, "r");
|
105
|
+
if (jpg == NULL) rb_raise(rb_eArgError, "Sorry: cannot open file for showing image (%s)\n", filename);
|
106
|
+
unsigned char *buff;
|
107
|
+
int len, rd_len;
|
108
|
+
int buff_len = 256000;
|
109
|
+
buff = ALLOC_N(unsigned char, buff_len);
|
110
|
+
len = 0;
|
111
|
+
while ((rd_len = fread(buff, 1, buff_len, jpg)) == buff_len) len += buff_len;
|
112
|
+
len += rd_len;
|
113
|
+
fprintf(OF, "\t/Subtype /Image\n");
|
114
|
+
if (mask_obj_num > 0) {
|
115
|
+
if (!Is_monochrome(mask_obj_num)) fprintf(OF, "\t/SMask %i 0 R\n", mask_obj_num);
|
116
|
+
else fprintf(OF, "\t/Mask %i 0 R\n", mask_obj_num);
|
117
|
+
}
|
118
|
+
fprintf(OF, "\t/Width %i\n", width);
|
119
|
+
fprintf(OF, "\t/Height %i\n", height);
|
120
|
+
fprintf(OF, "%s", out_info);
|
121
|
+
fprintf(OF, "\t/Length %i\n\t>>\nstream\n", len);
|
122
|
+
if (len < buff_len) fwrite(buff, 1, len, OF);
|
123
|
+
else {
|
124
|
+
rewind(jpg);
|
125
|
+
while ((rd_len = fread(buff, 1, buff_len, jpg)) == buff_len) fwrite(buff, 1, buff_len, OF);
|
126
|
+
fwrite(buff, 1, rd_len, OF);
|
127
|
+
}
|
128
|
+
fprintf(OF, "\nendstream\n");
|
129
|
+
fclose(jpg);
|
130
|
+
}
|
131
|
+
|
132
|
+
void Write_JPG(JPG_Info *xo)
|
133
|
+
{
|
134
|
+
Write_Image_From_File(xo->filename, xo->width, xo->height,
|
135
|
+
"\t/Filter /DCTDecode\n\t/ColorSpace /DeviceRGB\n\t/BitsPerComponent 8\n", xo->mask_obj_num);
|
136
|
+
}
|
137
|
+
|
138
|
+
void Write_Sampled(Sampled_Info *xo)
|
139
|
+
{
|
140
|
+
fprintf(OF, "\n\t/Subtype /Image\n");
|
141
|
+
fprintf(OF, "\t/Filter /FlateDecode\n\t/Interpolate %s\n", (xo->interpolate)? "true":"false");
|
142
|
+
fprintf(OF, "\t/Height %i\n", xo->height);
|
143
|
+
fprintf(OF, "\t/Width %i\n", xo->width);
|
144
|
+
int i, len;
|
145
|
+
unsigned long new_len;
|
146
|
+
unsigned char *buffer;
|
147
|
+
switch (xo->image_type) {
|
148
|
+
case RGB_IMAGE:
|
149
|
+
fprintf(OF, "\t/ColorSpace /DeviceRGB\n");
|
150
|
+
fprintf(OF, "\t/BitsPerComponent 8\n");
|
151
|
+
break;
|
152
|
+
case CMYK_IMAGE:
|
153
|
+
fprintf(OF, "\t/ColorSpace /DeviceCMYK\n");
|
154
|
+
fprintf(OF, "\t/BitsPerComponent 8\n");
|
155
|
+
break;
|
156
|
+
case GRAY_IMAGE:
|
157
|
+
fprintf(OF, "\t/ColorSpace /DeviceGray\n");
|
158
|
+
fprintf(OF, "\t/BitsPerComponent 8\n");
|
159
|
+
break;
|
160
|
+
case MONO_IMAGE:
|
161
|
+
fprintf(OF, "\t/ImageMask true\n");
|
162
|
+
fprintf(OF, "\t/BitsPerComponent 1\n");
|
163
|
+
if (!xo->reversed) fprintf(OF, "\t/Decode [0 1]\n");
|
164
|
+
else fprintf(OF, "\t/Decode [1 0]\n");
|
165
|
+
break;
|
166
|
+
default:
|
167
|
+
len = xo->lookup_len;
|
168
|
+
fprintf(OF, "\t/ColorSpace [ /Indexed /DeviceRGB %i <", xo->hival);
|
169
|
+
for (i = 0; i < len; i++) {
|
170
|
+
unsigned char c = xo->lookup[i];
|
171
|
+
if (c == 0) fprintf(OF, "00");
|
172
|
+
else if (c < 16) fprintf(OF, "0%x", c);
|
173
|
+
else fprintf(OF, "%x", c);
|
174
|
+
}
|
175
|
+
fprintf(OF, "> ]\n");
|
176
|
+
fprintf(OF, "\t/BitsPerComponent 8\n");
|
177
|
+
}
|
178
|
+
if (xo->mask_obj_num > 0) {
|
179
|
+
if (xo->image_type == MONO_IMAGE)
|
180
|
+
rb_raise(rb_eArgError, "Sorry: monochrome images must not have masks");
|
181
|
+
if (!Is_monochrome(xo->mask_obj_num)) fprintf(OF, "\t/SMask %i 0 R\n", xo->mask_obj_num);
|
182
|
+
else fprintf(OF, "\t/Mask %i 0 R\n", xo->mask_obj_num);
|
183
|
+
}
|
184
|
+
if (xo->value_mask_min >= 0 && xo->value_mask_max >= 0 &&
|
185
|
+
xo->value_mask_min <= 255 && xo->value_mask_max <= 255 && xo->value_mask_min <= xo->value_mask_max)
|
186
|
+
fprintf(OF, "\t/Mask [%i %i]\n", xo->value_mask_min, xo->value_mask_max);
|
187
|
+
new_len = (xo->length * 11)/10 + 100;
|
188
|
+
buffer = ALLOC_N(unsigned char, new_len);
|
189
|
+
if (flate_compress(buffer, &new_len, xo->image_data, xo->length) != FLATE_OK) {
|
190
|
+
free(buffer);
|
191
|
+
rb_raise(rb_eArgError, "Error compressing image data");
|
192
|
+
}
|
193
|
+
fprintf(OF, "\t/Length %li\n", new_len);
|
194
|
+
fprintf(OF, "\t>>\nstream\n");
|
195
|
+
if (fwrite(buffer, 1, new_len, OF) < new_len)
|
196
|
+
rb_raise(rb_eArgError, "Error writing image data");
|
197
|
+
free(buffer);
|
198
|
+
fprintf(OF, "\nendstream\nendobj\n");
|
199
|
+
}
|
200
|
+
|
201
|
+
void Create_Transform_from_Points( // transform maps (0,0), (1,0), and (0,1) to the given points
|
202
|
+
double llx, double lly, double lrx, double lry, double ulx, double uly,
|
203
|
+
double *a, double *b, double *c, double *d, double *e, double *f)
|
204
|
+
{
|
205
|
+
*e = llx; *f = lly; lrx -= llx; ulx -= llx; lry -= lly; uly -= lly;
|
206
|
+
*a = lrx; *b = lry; *c = ulx; *d = uly;
|
207
|
+
}
|
208
|
+
|
209
|
+
void Get_Image_Dest(FM *p, VALUE image_destination, double *dest)
|
210
|
+
{
|
211
|
+
image_destination = rb_Array(image_destination);
|
212
|
+
if (RARRAY(image_destination)->len != 6)
|
213
|
+
rb_raise(rb_eArgError, "Sorry: invalid image destination array: must have 6 entries");
|
214
|
+
int i;
|
215
|
+
for (i = 0; i < 6; i++) {
|
216
|
+
VALUE entry = rb_ary_entry(image_destination, i);
|
217
|
+
entry = rb_Float(entry);
|
218
|
+
if (i % 2 == 0)
|
219
|
+
dest[i] = convert_figure_to_output_x(p,NUM2DBL(entry));
|
220
|
+
else
|
221
|
+
dest[i] = convert_figure_to_output_y(p,NUM2DBL(entry));
|
222
|
+
}
|
223
|
+
}
|
224
|
+
|
225
|
+
static void Show_JPEG(FM *p, char *filename, int width, int height, double *dest, int subtype, int mask_obj_num)
|
226
|
+
{
|
227
|
+
JPG_Info *xo = ALLOC(JPG_Info);
|
228
|
+
xo->xobj_subtype = subtype;
|
229
|
+
double llx = dest[0], lly = dest[1], lrx = dest[2], lry = dest[3], ulx = dest[4], uly = dest[5];
|
230
|
+
double a, b, c, d, e, f; // the transform to position the image
|
231
|
+
xo->next = xobj_list;
|
232
|
+
xobj_list = (XObject_Info *)xo;
|
233
|
+
xo->xo_num = next_available_xo_number++;
|
234
|
+
xo->obj_num = next_available_object_number++;
|
235
|
+
xo->filename = ALLOC_N(char, strlen(filename)+1);
|
236
|
+
strcpy(xo->filename, filename);
|
237
|
+
xo->width = width;
|
238
|
+
xo->height = height;
|
239
|
+
xo->mask_obj_num = mask_obj_num;
|
240
|
+
Create_Transform_from_Points(llx, lly, lrx, lry, ulx, uly, &a, &b, &c, &d, &e, &f);
|
241
|
+
fprintf(TF, "q %0.2f %0.2f %0.2f %0.2f %0.2f %0.2f cm /XObj%i Do Q\n", a, b, c, d, e, f, xo->xo_num);
|
242
|
+
update_bbox(p, llx, lly);
|
243
|
+
update_bbox(p, lrx, lry);
|
244
|
+
update_bbox(p, ulx, uly);
|
245
|
+
update_bbox(p, lrx+ulx-llx, lry+uly-lly);
|
246
|
+
}
|
247
|
+
|
248
|
+
void c_show_jpg(FM *p, char *filename, int width, int height, double *dest, int mask_obj_num)
|
249
|
+
{
|
250
|
+
Show_JPEG(p, filename, width, height, dest, JPG_SUBTYPE, mask_obj_num);
|
251
|
+
}
|
252
|
+
|
253
|
+
VALUE FM_private_show_jpg(VALUE fmkr, VALUE filename, VALUE width, VALUE height, VALUE image_destination, VALUE mask_obj_num)
|
254
|
+
{
|
255
|
+
double dest[6];
|
256
|
+
FM *p = Get_FM(fmkr);
|
257
|
+
if (constructing_path) rb_raise(rb_eArgError, "Sorry: must finish with current path before calling show_jpg");
|
258
|
+
Get_Image_Dest(p, image_destination, dest);
|
259
|
+
width = rb_Integer(width);
|
260
|
+
height = rb_Integer(height);
|
261
|
+
mask_obj_num = rb_Integer(mask_obj_num);
|
262
|
+
filename = rb_String(filename);
|
263
|
+
c_show_jpg(p, RSTRING(filename)->ptr, NUM2INT(width), NUM2INT(height), dest, NUM2INT(mask_obj_num));
|
264
|
+
return fmkr;
|
265
|
+
}
|
266
|
+
|
267
|
+
VALUE c_private_create_image_data(FM *p, double **data, long num_cols, long num_rows,
|
268
|
+
int first_row, int last_row, int first_column, int last_column,
|
269
|
+
double min_value, double max_value, int max_code, int if_below_range, int if_above_range)
|
270
|
+
{
|
271
|
+
if (first_column < 0) first_column += num_cols;
|
272
|
+
if (first_column < 0 || first_column >= num_cols)
|
273
|
+
rb_raise(rb_eArgError, "Sorry: invalid first_column specification (%i)", first_column);
|
274
|
+
if (last_column < 0) last_column += num_cols;
|
275
|
+
if (last_column < 0 || last_column >= num_cols)
|
276
|
+
rb_raise(rb_eArgError, "Sorry: invalid last_column specification (%i)", last_column);
|
277
|
+
if (first_row < 0) first_row += num_rows;
|
278
|
+
if (first_row < 0 || first_row >= num_rows)
|
279
|
+
rb_raise(rb_eArgError, "Sorry: invalid first_row specification (%i)", first_row);
|
280
|
+
if (last_row < 0) last_row += num_rows;
|
281
|
+
if (last_row < 0 || last_row >= num_rows)
|
282
|
+
rb_raise(rb_eArgError, "Sorry: invalid last_row specification (%i)", last_row);
|
283
|
+
if (min_value >= max_value)
|
284
|
+
rb_raise(rb_eArgError, "Sorry: invalid range specification: min %g max %g", min_value, max_value);
|
285
|
+
if (max_code <= 0 || max_code > 255)
|
286
|
+
rb_raise(rb_eArgError, "Sorry: invalid max_code specification (%i)", max_code);
|
287
|
+
if (if_below_range < 0 || if_below_range > 255)
|
288
|
+
rb_raise(rb_eArgError, "Sorry: invalid if_below_range specification (%i)", if_below_range);
|
289
|
+
if (if_above_range < 0 || if_above_range > 255)
|
290
|
+
rb_raise(rb_eArgError, "Sorry: invalid if_above_range specification (%i)", if_above_range);
|
291
|
+
int i, j, k, width = last_column - first_column + 1, height = last_row - first_row + 1;
|
292
|
+
int sz = width * height;
|
293
|
+
if (sz <= 0) rb_raise(rb_eArgError, "Sorry: invalid data specification: width (%i) height (%i)", width, height);
|
294
|
+
char *buff = ALLOC_N(char, sz);
|
295
|
+
for (k = 0, i = first_row; i <= last_row; i++) {
|
296
|
+
double *row = data[i];
|
297
|
+
for (j = first_column; j <= last_column; j++) {
|
298
|
+
double val = row[j];
|
299
|
+
if (val < min_value) buff[k++] = if_below_range;
|
300
|
+
else if (val > max_value) buff[k++] = if_above_range;
|
301
|
+
else {
|
302
|
+
val = max_code * (val - min_value)/(max_value - min_value);
|
303
|
+
buff[k++] = ROUND(val);
|
304
|
+
}
|
305
|
+
}
|
306
|
+
}
|
307
|
+
VALUE result = rb_str_new(buff, sz);
|
308
|
+
free(buff);
|
309
|
+
return result;
|
310
|
+
}
|
311
|
+
|
312
|
+
VALUE FM_private_create_image_data(VALUE fmkr, VALUE data,
|
313
|
+
VALUE first_row, VALUE last_row, VALUE first_column, VALUE last_column,
|
314
|
+
VALUE min_value, VALUE max_value, VALUE max_code, VALUE if_below_range, VALUE if_above_range)
|
315
|
+
{
|
316
|
+
FM *p = Get_FM(fmkr);
|
317
|
+
long num_cols, num_rows;
|
318
|
+
double **ary = Dtable_Ptr(data, &num_cols, &num_rows);
|
319
|
+
first_row = rb_Integer(first_row);
|
320
|
+
last_row = rb_Integer(last_row);
|
321
|
+
first_column = rb_Integer(first_column);
|
322
|
+
last_column = rb_Integer(last_column);
|
323
|
+
max_code = rb_Integer(max_code);
|
324
|
+
if_below_range = rb_Integer(if_below_range);
|
325
|
+
if_above_range = rb_Integer(if_above_range);
|
326
|
+
min_value = rb_Float(min_value);
|
327
|
+
max_value = rb_Float(max_value);
|
328
|
+
return c_private_create_image_data(p, ary, num_cols, num_rows,
|
329
|
+
NUM2INT(first_row), NUM2INT(last_row), NUM2INT(first_column), NUM2INT(last_column),
|
330
|
+
NUM2DBL(min_value), NUM2DBL(max_value), NUM2INT(max_code), NUM2INT(if_below_range), NUM2INT(if_above_range));
|
331
|
+
}
|
332
|
+
|
333
|
+
static VALUE c_private_create_monochrome_image_data(FM *p, double **data, long num_cols, long num_rows,
|
334
|
+
int first_row, int last_row, int first_column, int last_column,
|
335
|
+
double boundary, bool reversed)
|
336
|
+
{
|
337
|
+
if (first_column < 0) first_column += num_cols;
|
338
|
+
if (first_column < 0 || first_column >= num_cols)
|
339
|
+
rb_raise(rb_eArgError, "Sorry: invalid first_column specification (%i)", first_column);
|
340
|
+
if (last_column < 0) last_column += num_cols;
|
341
|
+
if (last_column < 0 || last_column >= num_cols)
|
342
|
+
rb_raise(rb_eArgError, "Sorry: invalid last_column specification (%i)", last_column);
|
343
|
+
if (first_row < 0) first_row += num_rows;
|
344
|
+
if (first_row < 0 || first_row >= num_rows)
|
345
|
+
rb_raise(rb_eArgError, "Sorry: invalid first_row specification (%i)", first_row);
|
346
|
+
if (last_row < 0) last_row += num_rows;
|
347
|
+
if (last_row < 0 || last_row >= num_rows)
|
348
|
+
rb_raise(rb_eArgError, "Sorry: invalid last_row specification (%i)", last_row);
|
349
|
+
int i, j, k, width = last_column - first_column + 1, height = last_row - first_row + 1, bytes_per_row = (width+7)/8;
|
350
|
+
int sz = bytes_per_row * 8 * height;
|
351
|
+
if (sz <= 0) rb_raise(rb_eArgError, "Sorry: invalid data specification: width (%i) height (%i)", width, height);
|
352
|
+
// to simplify the process, do it in two stages: first get the values and then pack the bits
|
353
|
+
char *buff = ALLOC_N(char, sz);
|
354
|
+
for (k = 0, i = first_row; i <= last_row; i++) {
|
355
|
+
double *row = data[i];
|
356
|
+
for (j = first_column; j <= last_column; j++) {
|
357
|
+
double val = row[j];
|
358
|
+
buff[k++] = (reversed)? (val <= boundary) : (val > boundary);
|
359
|
+
}
|
360
|
+
for (j = last_column+1; j < bytes_per_row * 8; j++) {
|
361
|
+
buff[k++] = 0;
|
362
|
+
}
|
363
|
+
}
|
364
|
+
int num_bytes = (sz+7) >> 3;
|
365
|
+
char *bits = ALLOC_N(char, num_bytes), c = 0;
|
366
|
+
int num_bits = num_bytes << 3;
|
367
|
+
for (i = 0, k = -1; i < num_bits; i++) {
|
368
|
+
int bit = (i < sz)? buff[i] : 0;
|
369
|
+
int which_bit = i & 7;
|
370
|
+
if (which_bit != 0) c |= bit << (7-which_bit);
|
371
|
+
else {
|
372
|
+
if (k >= 0) bits[k] = c;
|
373
|
+
k++; c = bit << 7;
|
374
|
+
}
|
375
|
+
}
|
376
|
+
bits[k] = c;
|
377
|
+
VALUE result = rb_str_new(bits, num_bytes);
|
378
|
+
free(bits); free(buff);
|
379
|
+
return result;
|
380
|
+
}
|
381
|
+
|
382
|
+
VALUE FM_private_create_monochrome_image_data(VALUE fmkr, VALUE data,
|
383
|
+
VALUE first_row, VALUE last_row, VALUE first_column, VALUE last_column,
|
384
|
+
VALUE boundary, VALUE reverse)
|
385
|
+
{
|
386
|
+
FM *p = Get_FM(fmkr);
|
387
|
+
long num_cols, num_rows;
|
388
|
+
double **ary = Dtable_Ptr(data, &num_cols, &num_rows);
|
389
|
+
first_row = rb_Integer(first_row);
|
390
|
+
last_row = rb_Integer(last_row);
|
391
|
+
first_column = rb_Integer(first_column);
|
392
|
+
last_column = rb_Integer(last_column);
|
393
|
+
boundary = rb_Float(boundary);
|
394
|
+
return c_private_create_monochrome_image_data(p, ary, num_cols, num_rows,
|
395
|
+
NUM2INT(first_row), NUM2INT(last_row), NUM2INT(first_column), NUM2INT(last_column),
|
396
|
+
NUM2DBL(boundary), reverse != Qfalse);
|
397
|
+
}
|
398
|
+
|
399
|
+
int c_private_show_image(FM *p, int image_type, double *dest, bool interpolate, bool reversed, int w, int h, unsigned char* data, int len,
|
400
|
+
int value_mask_min, int value_mask_max, int hival, unsigned char* lookup, int lookup_len, int mask_obj_num)
|
401
|
+
{
|
402
|
+
Sampled_Info *xo = ALLOC(Sampled_Info);
|
403
|
+
xo->xobj_subtype = SAMPLED_SUBTYPE;
|
404
|
+
double llx = dest[0], lly = dest[1], lrx = dest[2], lry = dest[3], ulx = dest[4], uly = dest[5];
|
405
|
+
double a, b, c, d, e, f; // the transform to position the image
|
406
|
+
int ir, ic, id;
|
407
|
+
xo->next = xobj_list;
|
408
|
+
xobj_list = (XObject_Info *)xo;
|
409
|
+
xo->xo_num = next_available_xo_number++;
|
410
|
+
xo->obj_num = next_available_object_number++;
|
411
|
+
xo->image_data = ALLOC_N(unsigned char, len);
|
412
|
+
xo->length = len;
|
413
|
+
xo->interpolate = interpolate;
|
414
|
+
xo->reversed = reversed;
|
415
|
+
MEMCPY(xo->image_data, data, unsigned char, len);
|
416
|
+
xo->image_type = image_type;
|
417
|
+
if (image_type != COLORMAP_IMAGE) xo->lookup = NULL;
|
418
|
+
else {
|
419
|
+
if ((hival+1)*3 > lookup_len)
|
420
|
+
rb_raise(rb_eArgError, "Sorry: color space hival (%i) is too large for length of lookup table (%i)", hival, lookup_len);
|
421
|
+
xo->hival = hival;
|
422
|
+
lookup_len = (hival+1) * 3;
|
423
|
+
xo->lookup = ALLOC_N(unsigned char, lookup_len);
|
424
|
+
xo->lookup_len = lookup_len;
|
425
|
+
MEMCPY(xo->lookup, lookup, unsigned char, lookup_len);
|
426
|
+
}
|
427
|
+
xo->width = w;
|
428
|
+
xo->height = h;
|
429
|
+
|
430
|
+
if (0) {
|
431
|
+
printf("len=%i w=%i h=%i\ndata\n\n", len, w, h);
|
432
|
+
for (ir=0; ir<h; ir++) {
|
433
|
+
for (ic=0; ic<w; ic++) {
|
434
|
+
id = (int)data[ir*h+ic];
|
435
|
+
printf("%3i ",id);
|
436
|
+
}
|
437
|
+
printf("\n");
|
438
|
+
}
|
439
|
+
|
440
|
+
|
441
|
+
printf("\n\nxo->image_data\n");
|
442
|
+
for (ir=0; ir<h; ir++) {
|
443
|
+
for (ic=0; ic<w; ic++) {
|
444
|
+
id = (int)xo->image_data[ir*h+ic];
|
445
|
+
printf("%3i ",id);
|
446
|
+
}
|
447
|
+
printf("\n\n");
|
448
|
+
}
|
449
|
+
}
|
450
|
+
|
451
|
+
|
452
|
+
xo->value_mask_min = value_mask_min;
|
453
|
+
xo->value_mask_max = value_mask_max;
|
454
|
+
xo->mask_obj_num = mask_obj_num;
|
455
|
+
if (mask_obj_num == -1) return xo->obj_num; // this image is being used as an opacity mask
|
456
|
+
Create_Transform_from_Points(llx, lly, lrx, lry, ulx, uly, &a, &b, &c, &d, &e, &f);
|
457
|
+
fprintf(TF, "q %0.2f %0.2f %0.2f %0.2f %0.2f %0.2f cm /XObj%i Do Q\n", a, b, c, d, e, f, xo->xo_num);
|
458
|
+
update_bbox(p, llx, lly);
|
459
|
+
update_bbox(p, lrx, lry);
|
460
|
+
update_bbox(p, ulx, uly);
|
461
|
+
update_bbox(p, lrx+ulx-llx, lry+uly-lly);
|
462
|
+
return xo->obj_num;
|
463
|
+
}
|
464
|
+
|
465
|
+
static VALUE private_show_image(int image_type, VALUE fmkr, VALUE llx, VALUE lly, VALUE lrx, VALUE lry,
|
466
|
+
VALUE ulx, VALUE uly, VALUE interpolate, VALUE reversed, VALUE w, VALUE h, VALUE data, VALUE value_mask_min, VALUE value_mask_max,
|
467
|
+
VALUE hival, VALUE lookup, VALUE mask_obj_num)
|
468
|
+
{
|
469
|
+
double dest[6];
|
470
|
+
unsigned char *lookup_str=NULL;
|
471
|
+
int mask_min = 256, mask_max = 256, lookup_len=0, hivalue=0;
|
472
|
+
FM *p = Get_FM(fmkr);
|
473
|
+
if (constructing_path) rb_raise(rb_eArgError, "Sorry: must finish with current path before calling show_image");
|
474
|
+
data = rb_String(data);
|
475
|
+
llx = rb_Float(llx);
|
476
|
+
lly = rb_Float(lly);
|
477
|
+
lrx = rb_Float(lrx);
|
478
|
+
lry = rb_Float(lry);
|
479
|
+
ulx = rb_Float(ulx);
|
480
|
+
uly = rb_Float(uly);
|
481
|
+
w = rb_Integer(w);
|
482
|
+
h = rb_Integer(h);
|
483
|
+
mask_obj_num = rb_Integer(mask_obj_num);
|
484
|
+
if (image_type == COLORMAP_IMAGE) {
|
485
|
+
value_mask_min = rb_Integer(value_mask_min); mask_min = NUM2INT(value_mask_min);
|
486
|
+
value_mask_max = rb_Integer(value_mask_max); mask_max = NUM2INT(value_mask_max);
|
487
|
+
hival = rb_Integer(hival);
|
488
|
+
hivalue = NUM2INT(hival);
|
489
|
+
lookup = rb_String(lookup);
|
490
|
+
lookup_str = (unsigned char *)(RSTRING(lookup)->ptr);
|
491
|
+
lookup_len = RSTRING(lookup)->len;
|
492
|
+
}
|
493
|
+
dest[0] = convert_figure_to_output_x(p,NUM2DBL(llx));
|
494
|
+
dest[1] = convert_figure_to_output_y(p,NUM2DBL(lly));
|
495
|
+
dest[2] = convert_figure_to_output_x(p,NUM2DBL(lrx));
|
496
|
+
dest[3] = convert_figure_to_output_y(p,NUM2DBL(lry));
|
497
|
+
dest[4] = convert_figure_to_output_x(p,NUM2DBL(ulx));
|
498
|
+
dest[5] = convert_figure_to_output_y(p,NUM2DBL(uly));
|
499
|
+
int obj_num = c_private_show_image(p, image_type, dest, (interpolate != Qfalse), (reversed == Qtrue), NUM2INT(w), NUM2INT(h),
|
500
|
+
(unsigned char *)RSTRING(data)->ptr, RSTRING(data)->len, mask_min, mask_max, hivalue, lookup_str, lookup_len, NUM2INT(mask_obj_num));
|
501
|
+
return INT2FIX(obj_num);
|
502
|
+
}
|
503
|
+
|
504
|
+
VALUE FM_private_show_rgb_image(VALUE fmkr, VALUE llx, VALUE lly, VALUE lrx, VALUE lry,
|
505
|
+
VALUE ulx, VALUE uly, VALUE interpolate, VALUE w, VALUE h, VALUE data, VALUE mask_obj_num)
|
506
|
+
{
|
507
|
+
return private_show_image(RGB_IMAGE, fmkr, llx, lly, lrx, lry, ulx, uly, interpolate, Qfalse, w, h, data, Qnil, Qnil, Qnil, Qnil, mask_obj_num);
|
508
|
+
}
|
509
|
+
|
510
|
+
VALUE FM_private_show_cmyk_image(VALUE fmkr, VALUE llx, VALUE lly, VALUE lrx, VALUE lry,
|
511
|
+
VALUE ulx, VALUE uly, VALUE interpolate, VALUE w, VALUE h, VALUE data, VALUE mask_obj_num)
|
512
|
+
{
|
513
|
+
return private_show_image(CMYK_IMAGE, fmkr, llx, lly, lrx, lry, ulx, uly, interpolate, Qfalse, w, h, data, Qnil, Qnil, Qnil, Qnil, mask_obj_num);
|
514
|
+
}
|
515
|
+
|
516
|
+
VALUE FM_private_show_grayscale_image(VALUE fmkr, VALUE llx, VALUE lly, VALUE lrx, VALUE lry,
|
517
|
+
VALUE ulx, VALUE uly, VALUE interpolate, VALUE w, VALUE h, VALUE data, VALUE mask_obj_num)
|
518
|
+
{
|
519
|
+
return private_show_image(GRAY_IMAGE, fmkr, llx, lly, lrx, lry, ulx, uly, interpolate, Qfalse, w, h, data, Qnil, Qnil, Qnil, Qnil, mask_obj_num);
|
520
|
+
}
|
521
|
+
|
522
|
+
VALUE FM_private_show_monochrome_image(VALUE fmkr, VALUE llx, VALUE lly, VALUE lrx, VALUE lry,
|
523
|
+
VALUE ulx, VALUE uly, VALUE interpolate, VALUE reversed, VALUE w, VALUE h, VALUE data, VALUE mask_obj_num)
|
524
|
+
{
|
525
|
+
return private_show_image(MONO_IMAGE, fmkr, llx, lly, lrx, lry, ulx, uly, interpolate, reversed,
|
526
|
+
w, h, data, Qnil, Qnil, Qnil, Qnil, mask_obj_num);
|
527
|
+
}
|
528
|
+
|
529
|
+
VALUE FM_private_show_image(VALUE fmkr, VALUE llx, VALUE lly, VALUE lrx, VALUE lry,
|
530
|
+
VALUE ulx, VALUE uly, VALUE interpolate, VALUE w, VALUE h, VALUE data,
|
531
|
+
VALUE value_mask_min, VALUE value_mask_max, VALUE hival, VALUE lookup, VALUE mask_obj_num)
|
532
|
+
{
|
533
|
+
return private_show_image(COLORMAP_IMAGE, fmkr, llx, lly, lrx, lry, ulx, uly, interpolate, Qfalse, w, h, data,
|
534
|
+
value_mask_min, value_mask_max, hival, lookup, mask_obj_num);
|
535
|
+
}
|
536
|
+
|