1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
|
//
// PDF documentation tool to generate a png image from a Doxygen `@code`
// segment with international characters for the Fast Light Tool Kit (FLTK).
//
// Copyright 2025 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
// file is missing or damaged, see the license at:
//
// https://www.fltk.org/COPYING.php
//
// Please see the following page on how to report bugs and issues:
//
// https://www.fltk.org/bugs.php
//
//
// Our documentation for the FLTK unicode contains international characters
// to illustrate use of non ASCII characters in the GUI. To generate PDF
// output, Doxygen uses LaTeX which can not easily handle UTF-8 characters
// beyond Western encoding. This tool generates PNG images from code segments
// containing international characters so that they can be included in the
// PDF documentation instead of the code segments with UTF-8 characters.
//
// Notes:
// - This program is work in progress...
// - The PDF generation process (CMake) calls it once for each source file
// that needs image generation. The loop over all commandline arguments is
// currently not necessary but kept for potential extensions.
// - The program exits silently if no commandline is given.
// - If the terminating "\endcode_international" line is missing or misspelled,
// the program reads the "code" until the end of the file is reached and
// terminates w/o error message. This could be improved...
#include <FL/Fl_Window.H>
#include <FL/Fl_Group.H>
#include <FL/filename.H>
#include <FL/fl_draw.H>
#include <FL/Fl_Image_Surface.H>
#include <FL/Fl_PNG_Image.H>
#include "../fluid/widgets/Code_Editor.h"
#include "../fluid/widgets/Code_Viewer.h"
#include "../fluid/widgets/Style_Parser.h"
#include <stdio.h>
#include <algorithm>
Fl_Window* window = nullptr;
Fl_Group* group = nullptr;
fld::widget::Code_Viewer* code_viewer = nullptr;
int line_height = 10;
void create_window() {
window = new Fl_Window(1024, 100);
group = new Fl_Group(0, 0, 1024, 100);
group->color(0xf7f7ff00);
group->box(FL_FLAT_BOX);
code_viewer = new fld::widget::Code_Viewer(5, 5, 1014, 94);
code_viewer->box(FL_FLAT_BOX);
code_viewer->color(0xf7f7ff00);
code_viewer->textsize(30);
// code_viewer->cursor_style(CARET_CURSOR);
window->resizable(group);
group->resizable(code_viewer);
// Make sure the display is opened.
Fl_Display_Device::display_device();
line_height = fl_height(code_viewer->textfont(), code_viewer->textsize());
line_height = std::max(line_height, fl_height(FL_COURIER, code_viewer->textsize()));
line_height = std::max(line_height, fl_height(FL_COURIER_BOLD, code_viewer->textsize()));
line_height = std::max(line_height, fl_height(FL_COURIER_ITALIC, code_viewer->textsize()));
line_height = std::max(line_height, fl_height(FL_COURIER_BOLD_ITALIC, code_viewer->textsize()));
}
void save_snapshot(const char* code, const char* filename) {
// fprintf(stderr, "\\code\n%s\n\\endcode\n", code);
code_viewer->buffer()->text(code);
int n_lines = 1;
for (const char* s=code; *s; ++s) if (*s == '\n') n_lines++;
// 300 dpi for 7 inches = 2100 pixels
window->size(2100, (line_height * n_lines) + 18 );
// Generate the Image Surface
Fl_Image_Surface *srfc = new Fl_Image_Surface(window->w(), window->h());
// Draw the window and its content
Fl_Image_Surface::push_current(srfc);
srfc->draw(group, 0, 0);
fl_rect(0, 0, window->w(), window->h(), 0xccccff00);
Fl_Image_Surface::pop_current();
// fprintf(stderr, " Saving to \"%s\".\n", filename);
// Write the generated image
Fl_RGB_Image *img = srfc->image();
fl_write_png(filename, img);
// Clean up
delete img;
delete srfc;
}
/**
Main entry point for the PDF documentation helper tool.
The app scans the input file for the `\code_international{"filename"}`
directive, reads the following code segment until
`\endcode_international`, and generates a PNG image file with the given
filename containing the code segment rendered with FLTK's
code rendering capabilities.
\param[in] argc Argument count
\param[in] argv a list of input files with documentation in Doxygen format
\return Exit code (0 for success, non-zero for failure)
*/
int main(int argc, char *argv[]) {
int ret = 0;
char line[1024];
char cwd[FL_PATH_MAX];
// fl_getcwd(cwd, FL_PATH_MAX-1);
// fprintf(stderr, "code_snapshot:\n");
// fprintf(stderr, "Working directory is \"%s\".\n", cwd);
create_window();
for (int i = 1; i < argc; i++) {
FILE* f = fl_fopen(argv[i], "rb");
if (!f) {
fl_getcwd(cwd, FL_PATH_MAX-1);
fprintf(stderr, "code_snapshot:\nCan't open file \"%s\".\n", argv[i]);
fprintf(stderr, "Working directory is \"%s\".\n", cwd);
ret = -1;
break;
}
// fprintf(stderr, "Reading \"%s\".\n", argv[i]);
std::string code;
std::string filename;
bool in_code_block = false;
for (;;) {
fgets(line, 1023, f);
if (feof(f)) break;
if (in_code_block) {
if (strstr(line, "\\endcode_international")) {
if (!code.empty()) {
code.resize(code.size() - 1);
save_snapshot(code.c_str(), filename.c_str());
}
in_code_block = false;
code = "";
} else {
code += line;
}
} else {
if (strstr(line, "\\code_international")) {
const char* fn_start = strstr(line, "{\"");
const char* fn_end = strstr(line, "\"}");
if (fn_start && fn_end && (fn_end > fn_start)) {
filename = std::string(fn_start+2, fn_end-fn_start-2);
in_code_block = true;
}
}
}
}
fclose(f);
}
delete window;
return ret;
}
|