Rewrite png2c.pl in C++.

This allows us to always generate icons during build,
and in the future remove a Perl dependency.
This commit is contained in:
whitequark 2015-11-04 06:10:38 +03:00
parent b23336b589
commit f76f76ff60
10 changed files with 169 additions and 22122 deletions

View File

@ -141,9 +141,6 @@ endif()
# components
if(WIN32)
add_subdirectory(tools)
endif()
add_subdirectory(src)
add_subdirectory(exposed)

View File

@ -51,10 +51,10 @@ for use due to bugs in this toolkit.
### Building for Windows
You will need CMake and a Windows cross-compiler.
You will need CMake, a Windows cross-compiler, and Wine with binfmt support.
On a Debian derivative (e.g. Ubuntu) these can be installed with:
apt-get install mingw-w64 cmake
apt-get install cmake mingw-w64 wine-binfmt
Before building, check out the submodules:

View File

@ -79,26 +79,30 @@ endif()
# generated files
# `$<TARGET_FILE:tool>` allows us to use binfmt support on Linux
# without special-casing anything; running `tool.exe` would succeed
# but unlike Windows, Linux does not have the machinery to map
# an invocation of `tool` to an executable `tool.exe` in $PATH.
file(GLOB icons "${CMAKE_CURRENT_SOURCE_DIR}/icons/*.png")
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/generated")
add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/generated/icons.cpp"
"${CMAKE_CURRENT_BINARY_DIR}/generated/icons.h"
COMMAND $<TARGET_FILE:png2c>
"${CMAKE_CURRENT_BINARY_DIR}/generated/icons.cpp"
"${CMAKE_CURRENT_BINARY_DIR}/generated/icons.h"
${icons}
DEPENDS png2c ${icons})
if(PERL_FOUND AND PERLMODULES_FOUND)
add_custom_command(
OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/built/icons.h"
"${CMAKE_CURRENT_SOURCE_DIR}/built/icons-proto.h"
COMMAND "${PERL_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/png2c.pl"
"${CMAKE_CURRENT_SOURCE_DIR}/built/icons.h"
"${CMAKE_CURRENT_SOURCE_DIR}/built/icons-proto.h"
"${CMAKE_CURRENT_SOURCE_DIR}"
MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/png2c.pl"
DEPENDENCIES ${icons})
add_custom_command(
OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/built/bitmapextra.table.h"
COMMAND "${PERL_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/pngchar2c.pl"
"${CMAKE_CURRENT_SOURCE_DIR}/built/bitmapextra.table.h"
"${CMAKE_CURRENT_SOURCE_DIR}"
MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/pngchar2c.pl"
DEPENDENCIES ${icons})
DEPENDS ${icons})
endif()
if(WIN32 AND NOT DISABLE_TTF2C)
@ -110,8 +114,10 @@ endif()
set(generated_HEADERS
built/bitmapextra.table.h
built/bitmapfont.table.h
built/icons-proto.h
built/icons.h)
${CMAKE_CURRENT_BINARY_DIR}/generated/icons.h)
set(generated_SOURCES
${CMAKE_CURRENT_BINARY_DIR}/generated/icons.cpp)
set_source_files_properties(${generated_HEADERS}
PROPERTIES GENERATED TRUE)
@ -306,6 +312,7 @@ add_executable(solvespace WIN32 MACOSX_BUNDLE
${platform_HEADERS}
${platform_SOURCES}
${platform_BUNDLED_RESOURCES}
${generated_SOURCES}
${generated_HEADERS}
${solvespace_HEADERS}
${solvespace_SOURCES})

View File

@ -1,40 +0,0 @@
/**** This is a generated file - do not edit ****/
extern unsigned char Icon_angle[24*24*3];
extern unsigned char Icon_arc[24*24*3];
extern unsigned char Icon_assemble[24*24*3];
extern unsigned char Icon_bezier[24*24*3];
extern unsigned char Icon_circle[24*24*3];
extern unsigned char Icon_constraint[24*24*3];
extern unsigned char Icon_construction[24*24*3];
extern unsigned char Icon_edges[24*24*3];
extern unsigned char Icon_equal[24*24*3];
extern unsigned char Icon_extrude[24*24*3];
extern unsigned char Icon_faces[24*24*3];
extern unsigned char Icon_hidden_lines[24*24*3];
extern unsigned char Icon_horiz[24*24*3];
extern unsigned char Icon_in3d[24*24*3];
extern unsigned char Icon_length[24*24*3];
extern unsigned char Icon_line[24*24*3];
extern unsigned char Icon_mesh[24*24*3];
extern unsigned char Icon_normal[24*24*3];
extern unsigned char Icon_ontoworkplane[24*24*3];
extern unsigned char Icon_other_supp[24*24*3];
extern unsigned char Icon_parallel[24*24*3];
extern unsigned char Icon_perpendicular[24*24*3];
extern unsigned char Icon_point[24*24*3];
extern unsigned char Icon_pointonx[24*24*3];
extern unsigned char Icon_rectangle[24*24*3];
extern unsigned char Icon_ref[24*24*3];
extern unsigned char Icon_same_orientation[24*24*3];
extern unsigned char Icon_shaded[24*24*3];
extern unsigned char Icon_sketch_in_3d[24*24*3];
extern unsigned char Icon_sketch_in_plane[24*24*3];
extern unsigned char Icon_step_rotate[24*24*3];
extern unsigned char Icon_step_translate[24*24*3];
extern unsigned char Icon_symmetric[24*24*3];
extern unsigned char Icon_tangent_arc[24*24*3];
extern unsigned char Icon_text[24*24*3];
extern unsigned char Icon_trim[24*24*3];
extern unsigned char Icon_vert[24*24*3];
extern unsigned char Icon_workplane[24*24*3];

File diff suppressed because it is too large Load Diff

View File

@ -1,52 +0,0 @@
#!/usr/bin/env perl
use strict;
use warnings;
use GD;
my ($out, $proto, $srcdir) = @ARGV;
defined($srcdir) or $srcdir = '.';
-d "$srcdir/icons" || die "$srcdir/icons/: directory not found";
open(OUT, ">$out") or die "$out: $!";
open(PROTO, ">$proto") or die "$proto: $!";
print OUT "/**** This is a generated file - do not edit ****/\n\n";
print PROTO "/**** This is a generated file - do not edit ****/\n\n";
for my $file (<$srcdir/icons/*.png>) {
next if $file =~ m#/char-[^/]+$#;
$file =~ m#/([^/]+)\.png$#;
my $base = "Icon_$1";
$base =~ y/-/_/;
open(PNG, $file) or die "$file: $!\n";
my $img = newFromPng GD::Image(\*PNG) or die;
$img->trueColor(1);
close PNG;
my ($width, $height) = $img->getBounds();
die "$file: $width, $height" if ($width != 24) or ($height != 24);
print PROTO "extern unsigned char $base\[24*24*3\];\n";
print OUT "unsigned char $base\[24*24*3] = {\n";
for(my $y = 0; $y < 24; $y++) {
for(my $x = 0; $x < 24; $x++) {
my $index = $img->getPixel($x, 23-$y);
my ($r, $g, $b) = $img->rgb($index);
if($r + $g + $b < 11) {
($r, $g, $b) = (30, 30, 30);
}
printf OUT " 0x%02x, 0x%02x, 0x%02x,\n", $r, $g, $b;
}
}
print OUT "};\n\n";
}
close PROTO;
close OUT;

View File

@ -4,7 +4,7 @@
// Copyright 2008-2013 Jonathan Westhues.
//-----------------------------------------------------------------------------
#include "solvespace.h"
#include <icons-proto.h>
#include "generated/icons.h"
const TextWindow::Color TextWindow::fgColors[] = {
{ 'd', RGBi(255, 255, 255) },

View File

@ -6,8 +6,7 @@
// Copyright 2008-2013 Jonathan Westhues.
//-----------------------------------------------------------------------------
#include "solvespace.h"
#include <icons-proto.h>
#include <icons.h>
#include "generated/icons.h"
static uint8_t SPACER[1];
static const struct {

View File

@ -1,4 +1,19 @@
include_directories(
${PNG_INCLUDE_DIRS})
link_directories(
${PNG_LIBRARY_DIRS})
if(WIN32)
add_executable(ttf2c
ttf2c.cpp)
target_link_libraries(ttf2c
comctl32)
endif()
add_executable(png2c
png2c.cpp)
target_link_libraries(png2c
${PNG_LIBRARIES})

125
tools/png2c.cpp Normal file
View File

@ -0,0 +1,125 @@
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <png.h>
#define die(msg) do { fprintf(stderr, "%s\n", msg); abort(); } while(0)
void write_png(FILE *out, const char *filename) {
FILE *fp = fopen(filename, "rb");
if (!fp)
die("png fopen failed");
png_byte header[8] = {};
if(fread(header, 1, 8, fp) != 8)
die("png fread failed");
if(png_sig_cmp(header, 0, 8))
die("png_sig_cmp failed");
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if(!png)
die("png_create_read_struct failed");
png_set_expand(png);
png_set_strip_alpha(png);
png_infop png_info = png_create_info_struct(png);
if (!png_info)
die("png_create_info_struct failed");
if (setjmp(png_jmpbuf(png)))
die("png_init_io failed");
png_init_io(png, fp);
png_set_sig_bytes(png, 8);
png_read_info(png, png_info);
int width = png_get_image_width(png, png_info);
int height = png_get_image_height(png, png_info);
if(width != 24 || height != 24)
die("not a 24x24 png");
png_read_update_info(png, png_info);
if (setjmp(png_jmpbuf(png)))
die("png_read_image failed");
png_bytepp image = (png_bytepp) malloc(sizeof(png_bytep) * height);
for (int y = 0; y < height; y++)
image[y] = (png_bytep) malloc(png_get_rowbytes(png, png_info));
png_read_image(png, (png_bytepp) image);
for(int y = height - 1; y >= 0; y--) {
for(int x = 0; x < (int)png_get_rowbytes(png, png_info); x += 3) {
unsigned char r = image[y][x + 0],
g = image[y][x + 1],
b = image[y][x + 2];
if(r + g + b < 11)
r = g = b = 30;
fprintf(out, " 0x%02x, 0x%02x, 0x%02x,\n", r, g, b);
}
}
for (int y = 0; y < height; y++)
free(image[y]);
free(image);
fclose(fp);
png_destroy_read_struct(&png, &png_info, NULL);
}
int main(int argc, char** argv) {
if(argc < 3) {
fprintf(stderr, "Usage: %s <source out> <header out> <png in>...\n",
argv[0]);
return 1;
}
FILE *source = fopen(argv[1], "wt");
if(!source)
die("source fopen failed");
FILE *header = fopen(argv[2], "wt");
if(!header)
die("header fopen failed");
fprintf(source, "/**** This is a generated file - do not edit ****/\n\n");
fprintf(header, "/**** This is a generated file - do not edit ****/\n\n");
for(int i = 3; i < argc; i++) {
const char *filename = argv[i];
if(strstr(filename, "char-"))
continue;
const char *basename = strrchr(filename, '/'); /* cmake uses / even on Windows */
if(basename == NULL) {
basename = filename;
} else {
basename++; // skip separator
}
char *stemname = (char*) calloc(strlen(basename), 1);
strncpy(stemname, basename, strchr(basename, '.') - basename);
for(size_t j = 0; j < strlen(stemname); j++) {
if(!isalnum(stemname[j]))
stemname[j] = '_';
}
fprintf(header, "extern unsigned char Icon_%s[24*24*3];\n", stemname);
fprintf(source, "unsigned char Icon_%s[24*24*3] = {\n", stemname);
write_png(source, filename);
fprintf(source, "};\n\n");
free(stemname);
}
fclose(source);
fclose(header);
}