Improve code snapshot generation for PDF docs (#1353)
Build and Test / build-linux (push) Has been cancelled
Build and Test / build-wayland (push) Has been cancelled
Build and Test / build-macos (push) Has been cancelled
Build and Test / build-windows (push) Has been cancelled

CMake: execute `code_snapshot` separately for each file we want to
  scan so we can create timestamps and generate PNG images only if
  the source file (e.g. unicode.dox) was modified.

documentation/src/unicode.dox: remove output folder `generated`, use
  only the filename. CMake sets the current working directory as needed.

util/code_snapshot.cxx: format and improve comments, reset code buffer
  so we can generate multiple images per input file.
This commit is contained in:
Albrecht Schlosser
2025-12-29 20:02:06 +01:00
parent 83fab8cb0f
commit a057e13fb4
3 changed files with 66 additions and 24 deletions
+37 -3
View File
@@ -202,11 +202,42 @@ if(FLTK_BUILD_PDF_DOCS)
@ONLY @ONLY
) )
# generate fltk.pdf # Generate code snapshots (images with international characters).
# Note: File names (even from different folders) must be unique !
set(image_output_dir "${CMAKE_CURRENT_BINARY_DIR}/generated")
set(_deps)
set(image_input_sources
${CMAKE_CURRENT_SOURCE_DIR}/src/unicode.dox
# ${CMAKE_CURRENT_SOURCE_DIR}/src/cmp.dox
# ${FLTK_SOURCE_DIR}/src/Fl.cxx # example source file
)
# Generate one custom command and one timestamp per input file
# so dependencies can be used to generate the images only if
# the source file was changes.
# Variable `_deps` is used to make the final PDF generation
# depend on all input files.
foreach(_infile ${image_input_sources})
get_filename_component(_name "${_infile}" NAME)
set(_timestamp ${image_output_dir}/${_name}.timestamp)
list(APPEND _deps ${_timestamp})
# create custom command
add_custom_command(
OUTPUT ${_timestamp}
COMMAND touch ${_timestamp}
COMMAND code_snapshot ${_infile}
DEPENDS ${_infile}
WORKING_DIRECTORY ${image_output_dir}
COMMENT "Generating code snapshots (PNG) from '${_infile}'"
)
endforeach()
# Now generate the PDF file (fltk.pdf)
add_custom_command( add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/fltk.pdf OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/fltk.pdf
COMMAND code_snapshot ${CMAKE_CURRENT_SOURCE_DIR}/src/unicode.dox
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/make_header COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/make_header
${DOXYGEN_EXECUTABLE} ${DOXYGEN_EXECUTABLE}
${CMAKE_CURRENT_BINARY_DIR}/fltk-title.tex ${CMAKE_CURRENT_BINARY_DIR}/fltk-title.tex
@@ -214,8 +245,11 @@ if(FLTK_BUILD_PDF_DOCS)
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE} COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE}
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/make_pdf COMMAND ${CMAKE_CURRENT_BINARY_DIR}/make_pdf
COMMAND cp -f latex/refman.pdf fltk.pdf COMMAND cp -f latex/refman.pdf fltk.pdf
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${DOXYFILE} DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in
${CMAKE_CURRENT_BINARY_DIR}/${DOXYFILE}.in
${CMAKE_CURRENT_BINARY_DIR}/${DOXYFILE}
${CMAKE_CURRENT_BINARY_DIR}/fltk-title.tex ${CMAKE_CURRENT_BINARY_DIR}/fltk-title.tex
${_deps} # source files processed to generate PNG's
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating PDF documentation" VERBATIM COMMENT "Generating PDF documentation" VERBATIM
) )
+3 -3
View File
@@ -22,7 +22,7 @@ are not yet implemented.
International code test for HTML and PDF: International code test for HTML and PDF:
\code_international{"generated/unicode_about.png"} \code_international{"unicode_about.png"}
// This is a test // This is a test
// 日本語テストテキスト // 日本語テストテキスト
// 中文测试文本 // 中文测试文本
@@ -70,11 +70,11 @@ doesn't break legacy ASCII code.
Functions to check and analyze UTF-8 text: Functions to check and analyze UTF-8 text:
fl_utf8test() - Check if a string contains valid UTF-8 fl_utf8test() - Check if a string contains valid UTF-8
\code \code_international{"unicode_hello.png"}
const char* text = "Hello 世界"; const char* text = "Hello 世界";
int result = fl_utf8test(text, strlen(text)); int result = fl_utf8test(text, strlen(text));
// Returns: 0=invalid, 1=ASCII, 2=2-byte chars, 3=3-byte chars, 4=4-byte chars // Returns: 0=invalid, 1=ASCII, 2=2-byte chars, 3=3-byte chars, 4=4-byte chars
\endcode \endcode_international
fl_utf8len() - Get the length in bytes of a UTF-8 octet fl_utf8len() - Get the length in bytes of a UTF-8 octet
\code \code
+26 -18
View File
@@ -18,11 +18,20 @@
// //
// Our documentation for the FLTK unicode contains international characters // Our documentation for the FLTK unicode contains international characters
// to illustrate use of non ASCII characters in the GUI. To generate PDF // 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 in // output, Doxygen uses LaTeX which can not easily handle UTF-8 characters
// beyond Western encoding. This tool generates PNG images from code segments // beyond Western encoding. This tool generates PNG images from code segments
// containing international characters so that they can be included in the // containing international characters so that they can be included in the
// PDF documentation instead of the code segments with UTF-8 characters. // 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_Window.H>
#include <FL/Fl_Group.H> #include <FL/Fl_Group.H>
@@ -54,7 +63,7 @@ void create_window() {
code_viewer->box(FL_FLAT_BOX); code_viewer->box(FL_FLAT_BOX);
code_viewer->color(0xf7f7ff00); code_viewer->color(0xf7f7ff00);
code_viewer->textsize(30); code_viewer->textsize(30);
//code_viewer->cursor_style(CARET_CURSOR); // code_viewer->cursor_style(CARET_CURSOR);
window->resizable(group); window->resizable(group);
group->resizable(code_viewer); group->resizable(code_viewer);
@@ -69,14 +78,13 @@ void create_window() {
line_height = std::max(line_height, fl_height(FL_COURIER_BOLD_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) void save_snapshot(const char* code, const char* filename) {
{ // fprintf(stderr, "\\code\n%s\n\\endcode\n", code);
// fprintf(stderr, "\\code\n%s\n\\endcode\n", code);
code_viewer->buffer()->text(code); code_viewer->buffer()->text(code);
int n_lines = 1; int n_lines = 1;
for (const char* s=code; *s; ++s) if (*s == '\n') n_lines++; for (const char* s=code; *s; ++s) if (*s == '\n') n_lines++;
// 300 dpi for 7 inches = 2000 pixels // 300 dpi for 7 inches = 2100 pixels
window->size(2100, (line_height * n_lines) + 18 ); window->size(2100, (line_height * n_lines) + 18 );
// Generate the Image Surface // Generate the Image Surface
@@ -88,7 +96,7 @@ void save_snapshot(const char* code, const char* filename)
fl_rect(0, 0, window->w(), window->h(), 0xccccff00); fl_rect(0, 0, window->w(), window->h(), 0xccccff00);
Fl_Image_Surface::pop_current(); Fl_Image_Surface::pop_current();
// fprintf(stderr, " Saving to \"%s\".\n", filename); // fprintf(stderr, " Saving to \"%s\".\n", filename);
// Write the generated image // Write the generated image
Fl_RGB_Image *img = srfc->image(); Fl_RGB_Image *img = srfc->image();
@@ -102,25 +110,24 @@ void save_snapshot(const char* code, const char* filename)
/** /**
Main entry point for the PDF documentation helper tool. Main entry point for the PDF documentation helper tool.
The app scans the input file for the `\\code_international{"filename"}` The app scans the input file for the `\code_international{"filename"}`
directive, reads the following code segment until directive, reads the following code segment until
`\\endcode_international`, and generates a PNG image file with the given `\endcode_international`, and generates a PNG image file with the given
filename containing the code segment rendered with FLTK's filename containing the code segment rendered with FLTK's
code rendering capabilities. code rendering capabilities.
\param argc Argument count \param[in] argc Argument count
\param argv a list of input files with documentation in Doxygen format \param[in] argv a list of input files with documentation in Doxygen format
\return Exit code (0 for success, non-zero for failure) \return Exit code (0 for success, non-zero for failure)
*/ */
int main(int argc, char *argv[]) int main(int argc, char *argv[]) {
{
int ret = 0; int ret = 0;
char line[1024]; char line[1024];
char cwd[FL_PATH_MAX]; char cwd[FL_PATH_MAX];
// fl_getcwd(cwd, FL_PATH_MAX-1); // fl_getcwd(cwd, FL_PATH_MAX-1);
// fprintf(stderr, "code_snapshot:\n"); // fprintf(stderr, "code_snapshot:\n");
// fprintf(stderr, "Working directory is \"%s\".\n", cwd); // fprintf(stderr, "Working directory is \"%s\".\n", cwd);
create_window(); create_window();
@@ -134,7 +141,7 @@ int main(int argc, char *argv[])
break; break;
} }
// fprintf(stderr, "Reading \"%s\".\n", argv[i]); // fprintf(stderr, "Reading \"%s\".\n", argv[i]);
std::string code; std::string code;
std::string filename; std::string filename;
@@ -145,10 +152,11 @@ int main(int argc, char *argv[])
if (in_code_block) { if (in_code_block) {
if (strstr(line, "\\endcode_international")) { if (strstr(line, "\\endcode_international")) {
if (!code.empty()) { if (!code.empty()) {
code.resize( code.size()-1 ); code.resize(code.size() - 1);
save_snapshot(code.c_str(), filename.c_str()); save_snapshot(code.c_str(), filename.c_str());
} }
in_code_block = false; in_code_block = false;
code = "";
} else { } else {
code += line; code += line;
} }