Replace libpng and libjpeg with stb_image in the web plug-in to fix conflicts with incompatible system versions of libpng

This commit is contained in:
rdb 2015-03-22 19:48:16 +01:00
parent 0ee5be581c
commit babc6726b2
7 changed files with 6366 additions and 233 deletions

View File

@ -18,8 +18,7 @@
// /MD. This links the plugin with the static C runtime library,
// instead of the dynamic runtime library, which is much better for
// distributing the plugin with the XPI and CAB interfaces. This
// requires that special /MT versions of OpenSSL, libjpeg, libpng,
// and zlib are available.
// requires that special /MT versions of OpenSSL and zlib are available.
#define _MT $[if $[P3D_PLUGIN_MT],_mt]
@ -114,8 +113,8 @@
// p3d_plugin.dll, the main entry point to the Core API.
//
#define BUILD_TARGET $[and $[HAVE_P3D_PLUGIN],$[HAVE_OPENSSL],$[HAVE_ZLIB],$[HAVE_JPEG],$[HAVE_PNG]]
#define USE_PACKAGES openssl$[_MT] zlib$[_MT] jpeg$[_MT] png$[_MT] x11
#define BUILD_TARGET $[and $[HAVE_P3D_PLUGIN],$[HAVE_OPENSSL],$[HAVE_ZLIB]]
#define USE_PACKAGES openssl$[_MT] zlib$[_MT] x11
#define TARGET p3d_plugin
#define LIB_PREFIX
#define BUILDING_DLL BUILDING_P3D_PLUGIN
@ -141,8 +140,8 @@
// libp3d_plugin_static.lib, the Core API as a static library (for p3dembed).
//
#define BUILD_TARGET $[and $[HAVE_P3D_PLUGIN],$[HAVE_OPENSSL],$[HAVE_ZLIB],$[HAVE_JPEG],$[HAVE_PNG]]
#define USE_PACKAGES openssl zlib jpeg png x11
#define BUILD_TARGET $[and $[HAVE_P3D_PLUGIN],$[HAVE_OPENSSL],$[HAVE_ZLIB]]
#define USE_PACKAGES openssl zlib x11
#define TARGET p3d_plugin_static
#define BUILDING_DLL BUILDING_P3D_PLUGIN

View File

@ -15,30 +15,11 @@
#include "p3dSplashWindow.h"
#include "wstring_encode.h"
// Stuff to use libpng.
#include <png.h>
// Stuff to use libjpeg.
extern "C" {
#include <jpeglib.h>
#include <jerror.h>
}
#include <setjmp.h>
struct my_error_mgr {
struct jpeg_error_mgr pub;
jmp_buf setjmp_buffer;
};
typedef struct my_error_mgr *my_error_ptr;
METHODDEF(void) my_error_exit (j_common_ptr cinfo) {
// cinfo->err really points to a my_error_mgr struct, so coerce pointer
my_error_ptr myerr = (my_error_ptr) cinfo->err;
// Return control to the setjmp point
longjmp(myerr->setjmp_buffer, 1);
}
// We use the public domain stb_image library for loading images.
// Define the stb_image implementation. We only use it in this unit.
#define STB_IMAGE_STATIC
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
// The number of pixels to move the block per byte downloaded, when we
// don't know the actual file size we're downloading.
@ -52,7 +33,7 @@ const double P3DSplashWindow::_unknown_progress_rate = 1.0 / 4096;
// them both into this class for reference.
////////////////////////////////////////////////////////////////////
P3DSplashWindow::
P3DSplashWindow(P3DInstance *inst, bool make_visible) :
P3DSplashWindow(P3DInstance *inst, bool make_visible) :
_inst(inst),
_fparams(inst->get_fparams()),
_wparams(inst->get_wparams())
@ -82,7 +63,7 @@ P3DSplashWindow(P3DInstance *inst, bool make_visible) :
////////////////////////////////////////////////////////////////////
// Function: P3DSplashWindow::Destructor
// Access: Public, Virtual
// Description:
// Description:
////////////////////////////////////////////////////////////////////
P3DSplashWindow::
~P3DSplashWindow() {
@ -259,191 +240,25 @@ read_image_data(ImageData &image, string &data,
return false;
}
// We only support JPEG or PNG images.
FILE *fp = NULL;
#ifdef _WIN32
wstring image_filename_w;
if (string_to_wstring(image_filename_w, image_filename)) {
fp = _wfopen(image_filename_w.c_str(), L"rb");
}
#else // _WIN32
fp = fopen(image_filename.c_str(), "rb");
#endif // _WIN32
nout << "Reading splash file image: " << image_filename << "\n";
if (fp == NULL) {
nout << "Couldn't open splash file image: " << image_filename << "\n";
return false;
}
unsigned char *imgdata = stbi_load(image_filename.c_str(), &image._width,
&image._height, &image._num_channels, 0);
// Check the magic number to determine which image type we have.
static const size_t magic_number_len = 2;
char magic_number[magic_number_len];
if (fread(magic_number, 1, magic_number_len, fp) != magic_number_len) {
nout << "Empty file: " << image_filename << "\n";
return false;
}
// Rewind to re-read the magic number below.
fseek(fp, 0, SEEK_SET);
bool result = false;
if ((char)magic_number[0] == (char)0xff &&
(char)magic_number[1] == (char)0xd8) {
// It's a jpeg image.
result = read_image_data_jpeg(image, data, fp, image_filename);
} else if (png_sig_cmp((png_bytep)magic_number, 0, magic_number_len) == 0) {
// It's a PNG image.
result = read_image_data_png(image, data, fp, image_filename);
} else {
nout << "Neither a JPEG nor a PNG image: " << image_filename << "\n";
result = false;
}
fclose(fp);
return result;
}
////////////////////////////////////////////////////////////////////
// Function: P3DSplashWindow::read_image_data_jpeg
// Access: Protected
// Description: Reads the image filename and sets image parameters
// width, height, num_channels, and data. Returns true
// on success, false on failure.
////////////////////////////////////////////////////////////////////
bool P3DSplashWindow::
read_image_data_jpeg(ImageData &image, string &data,
FILE *fp, const string &image_filename) {
// We set up the normal JPEG error routines, then override error_exit.
struct jpeg_decompress_struct cinfo;
struct my_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
JSAMPLE *buffer = NULL;
// Establish the setjmp return context for my_error_exit to use
if (setjmp(jerr.setjmp_buffer)) {
// If we get here, the JPEG code has signaled an error.
nout << "JPEG error decoding " << image_filename << "\n";
// We need to clean up the JPEG object, close the input file, and return.
jpeg_destroy_decompress(&cinfo);
if (buffer != NULL) {
delete[] buffer;
if (imgdata == NULL) {
nout << "Couldn't read splash file image: " << image_filename << "\n";
const char *reason = stbi_failure_reason();
if (reason != NULL) {
nout << "stbi_failure_reason: " << reason << "\n";
}
return false;
}
/* Now we can initialize the JPEG decompression object. */
jpeg_create_decompress(&cinfo);
jpeg_stdio_src(&cinfo, fp);
size_t data_size = image._width * image._height * image._num_channels;
data.resize(data_size);
memcpy(&data[0], imgdata, data_size);
jpeg_read_header(&cinfo, true);
cinfo.scale_num = 1;
cinfo.scale_denom = 1;
jpeg_start_decompress(&cinfo);
image._width = cinfo.output_width;
image._height = cinfo.output_height;
image._num_channels = cinfo.output_components;
int row_stride = image._width * image._num_channels;
size_t buffer_size = image._height * row_stride;
buffer = new JSAMPLE[buffer_size];
JSAMPLE *buffer_end = buffer + buffer_size;
JSAMPLE *rowptr = buffer;
while (cinfo.output_scanline < cinfo.output_height) {
assert(rowptr + row_stride <= buffer_end);
jpeg_read_scanlines(&cinfo, &rowptr, 1);
rowptr += row_stride;
}
jpeg_finish_decompress(&cinfo);
data.append((const char *)buffer, buffer_size);
delete[] buffer;
return true;
}
////////////////////////////////////////////////////////////////////
// Function: P3DSplashWindow::read_image_data_png
// Access: Protected
// Description: Reads the image filename and sets image parameters
// width, height, num_channels, and data. Returns true
// on success, false on failure.
////////////////////////////////////////////////////////////////////
bool P3DSplashWindow::
read_image_data_png(ImageData &image, string &data,
FILE *fp, const string &image_filename) {
png_structp png;
png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png == NULL) {
return false;
}
png_infop info;
info = png_create_info_struct(png);
if (info == NULL) {
png_destroy_read_struct(&png, NULL, NULL);
return false;
}
jmp_buf jmpbuf;
if (setjmp(jmpbuf)) {
// This is the ANSI C way to handle exceptions. If setjmp(),
// above, returns true, it means that libpng detected an exception
// while executing the code that reads the header info, below.
png_destroy_read_struct(&png, &info, NULL);
return false;
}
png_init_io(png, fp);
int transforms = PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_SHIFT;
// transforms |= PNG_TRANSFORM_STRIP_ALPHA;
png_read_png(png, info, transforms, NULL);
png_uint_32 width;
png_uint_32 height;
int bit_depth;
int color_type;
png_get_IHDR(png, info, &width, &height,
&bit_depth, &color_type, NULL, NULL, NULL);
image._width = width;
image._height = height;
switch (color_type) {
case PNG_COLOR_TYPE_RGB:
image._num_channels = 3;
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
image._num_channels = 4;
break;
default:
nout << "Unsupported color type: " << color_type << "\n";
png_destroy_read_struct(&png, &info, NULL);
return false;
}
int row_stride = image._width * image._num_channels;
png_bytep *row_pointers = png_get_rows(png, info);
for (int yi = 0; yi < image._height; ++yi) {
data.append((const char *)row_pointers[yi], row_stride);
}
png_destroy_read_struct(&png, &info, NULL);
stbi_image_free(imgdata);
return true;
}
@ -479,7 +294,7 @@ set_button_range(const ImageData &image) {
// But it can't be larger than the window itself.
_button_width = min(_button_width, _win_width);
_button_height = min(_button_height, _win_height);
// Compute the top-left corner of the button image in window
// coordinates.
_button_x = (_win_width - _button_width) / 2;

View File

@ -78,10 +78,6 @@ protected:
bool read_image_data(ImageData &image, string &data,
const string &image_filename);
bool read_image_data_jpeg(ImageData &image, string &data,
FILE *fp, const string &image_filename);
bool read_image_data_png(ImageData &image, string &data,
FILE *fp, const string &image_filename);
void get_bar_placement(int &bar_x, int &bar_y,
int &bar_width, int &bar_height);
void set_button_range(const ImageData &image);

File diff suppressed because it is too large Load Diff

View File

@ -83,7 +83,6 @@
#end bin_target
#begin bin_target
#define BUILD_TARGET $[and $[HAVE_JPEG],$[HAVE_PNG]]
#define USE_PACKAGES openssl zlib
#define TARGET p3dembed
#define LOCAL_LIBS plugin_common p3d_plugin_static
@ -115,7 +114,7 @@
// On Windows, we also need to build p3dembedw.exe, the non-console
// version of p3dembed.exe.
#define BUILD_TARGET $[and $[HAVE_JPEG],$[HAVE_PNG],$[WINDOWS_PLATFORM]]
#define BUILD_TARGET $[WINDOWS_PLATFORM]
#define USE_PACKAGES openssl zlib
#define TARGET p3dembedw
#define LOCAL_LIBS plugin_common p3d_plugin_static

View File

@ -366,10 +366,10 @@ if (RUNTIME):
if pkg in ["GTK2"]:
# Optional package(s) for runtime.
pass
elif pkg in ["OPENSSL", "ZLIB", "JPEG", "PNG"]:
elif pkg in ["OPENSSL", "ZLIB"]:
# Required packages for runtime.
if (PkgSkip(pkg)==1):
exit("Runtime must be compiled with OpenSSL, ZLib, JPEG and PNG support!")
exit("Runtime must be compiled with OpenSSL and ZLib support!")
else:
# Unused packages for runtime.
PkgDisable(pkg)
@ -383,9 +383,6 @@ if (INSTALLER and RTDIST):
if (INSTALLER) and (PkgSkip("PYTHON")) and (not RUNTIME) and GetTarget() == 'windows':
exit("Cannot build installer on Windows without python")
if (RTDIST) and (PkgSkip("JPEG")):
exit("Cannot build rtdist without jpeg")
if (RTDIST) and (PkgSkip("WX") and PkgSkip("FLTK")):
exit("Cannot build rtdist without wx or fltk")
@ -720,6 +717,8 @@ if (COMPILER=="GCC"):
SmartPkgEnable("VRPN", "", ("vrpn", "quat"), ("vrpn", "quat.h", "vrpn/vrpn_Types.h"))
SmartPkgEnable("BULLET", "bullet", ("BulletSoftBody", "BulletDynamics", "BulletCollision", "LinearMath"), ("bullet", "bullet/btBulletDynamicsCommon.h"))
SmartPkgEnable("VORBIS", "vorbisfile",("vorbisfile", "vorbis", "ogg"), ("ogg/ogg.h", "vorbis/vorbisfile.h"))
SmartPkgEnable("JPEG", "", ("jpeg"), "jpeglib.h")
SmartPkgEnable("PNG", "libpng", ("png"), "png.h", tool = "libpng-config")
rocket_libs = ("RocketCore", "RocketControls")
if (GetOptimize() <= 3):
@ -729,9 +728,7 @@ if (COMPILER=="GCC"):
rocket_libs += ("boost_python",)
SmartPkgEnable("ROCKET", "", rocket_libs, "Rocket/Core.h")
SmartPkgEnable("JPEG", "", ("jpeg"), "jpeglib.h")
SmartPkgEnable("OPENSSL", "openssl", ("ssl", "crypto"), ("openssl/ssl.h", "openssl/crypto.h"))
SmartPkgEnable("PNG", "libpng", ("png"), "png.h", tool = "libpng-config")
SmartPkgEnable("ZLIB", "zlib", ("z"), "zlib.h")
SmartPkgEnable("GTK2", "gtk+-2.0")
@ -773,12 +770,12 @@ if (COMPILER=="GCC"):
if (RUNTIME):
# For the runtime, all packages are required
for pkg in ["OPENSSL", "ZLIB", "JPEG", "PNG"]:
for pkg in ["OPENSSL", "ZLIB"]:
skips = []
if (pkg in PkgListGet() and PkgSkip(pkg)==1):
skips.append(pkg)
if skips:
exit("Runtime must be compiled with OpenSSL, ZLib, JPEG and PNG support (missing %s)" % (', '.join(skips)))
exit("Runtime must be compiled with OpenSSL and ZLib support (missing %s)" % (', '.join(skips)))
for pkg in MAYAVERSIONS:
if (PkgSkip(pkg)==0 and (pkg in SDK)):
@ -4747,7 +4744,7 @@ if (RTDIST or RUNTIME):
OPTS=['DIR:direct/src/plugin', 'BUILDING:P3D_PLUGIN', 'RUNTIME', 'OPENSSL']
TargetAdd('plugin_common.obj', opts=OPTS, input='plugin_common_composite1.cxx')
OPTS += ['ZLIB', 'JPEG', 'PNG', 'MSIMG']
OPTS += ['ZLIB', 'MSIMG']
TargetAdd('plugin_plugin.obj', opts=OPTS, input='p3d_plugin_composite1.cxx')
TargetAdd('plugin_mkdir_complete.obj', opts=OPTS, input='mkdir_complete.cxx')
TargetAdd('plugin_wstring_encode.obj', opts=OPTS, input='wstring_encode.cxx')
@ -4776,7 +4773,7 @@ if (RTDIST or RUNTIME):
TargetAdd(fname, input='libp3tinyxml.ilb')
if GetTarget() == 'darwin':
TargetAdd(fname, input='libp3subprocbuffer.ilb')
TargetAdd(fname, opts=['OPENSSL', 'ZLIB', 'JPEG', 'PNG', 'X11', 'ADVAPI', 'WINUSER', 'WINGDI', 'WINSHELL', 'WINCOMCTL', 'WINOLE', 'MSIMG'])
TargetAdd(fname, opts=['OPENSSL', 'ZLIB', 'X11', 'ADVAPI', 'WINUSER', 'WINGDI', 'WINSHELL', 'WINCOMCTL', 'WINOLE', 'MSIMG'])
TargetAdd("libp3d_plugin_static.ilb", input='plugin_get_twirl_data.obj')
if (PkgSkip("PYTHON")==0 and RTDIST):
@ -4960,7 +4957,7 @@ if (RUNTIME):
TargetAdd('panda3dw.exe', opts=['OPENSSL', 'ZLIB', 'WINGDI', 'WINUSER', 'WINSHELL', 'ADVAPI', 'WINSOCK2', 'WINOLE', 'CARBON'])
if (RTDIST):
OPTS=['BUILDING:P3D_PLUGIN', 'DIR:direct/src/plugin_standalone', 'DIR:direct/src/plugin', 'DIR:dtool/src/dtoolbase', 'DIR:dtool/src/dtoolutil', 'DIR:dtool/src/pystub', 'DIR:dtool/src/prc', 'DIR:dtool/src/dconfig', 'DIR:panda/src/express', 'DIR:panda/src/downloader', 'RUNTIME', 'P3DEMBED', 'OPENSSL', 'JPEG', 'PNG', 'ZLIB']
OPTS=['BUILDING:P3D_PLUGIN', 'DIR:direct/src/plugin_standalone', 'DIR:direct/src/plugin', 'DIR:dtool/src/dtoolbase', 'DIR:dtool/src/dtoolutil', 'DIR:dtool/src/pystub', 'DIR:dtool/src/prc', 'DIR:dtool/src/dconfig', 'DIR:panda/src/express', 'DIR:panda/src/downloader', 'RUNTIME', 'P3DEMBED', 'OPENSSL', 'ZLIB']
# This is arguably a big fat ugly hack, but doing it otherwise would complicate the build process considerably.
DefSymbol("P3DEMBED", "LINK_ALL_STATIC", "")
TargetAdd('plugin_standalone_panda3dBase.obj', opts=OPTS, input='panda3dBase.cxx')
@ -5007,7 +5004,7 @@ if (RTDIST):
TargetAdd('p3dembed.exe', input='libp3subprocbuffer.ilb')
TargetAdd('p3dembed.exe', input='libp3tinyxml.ilb')
TargetAdd('p3dembed.exe', input='libp3d_plugin_static.ilb')
TargetAdd('p3dembed.exe', opts=['NOICON', 'WINGDI', 'WINSOCK2', 'ZLIB', 'WINUSER', 'OPENSSL', 'JPEG', 'WINOLE', 'CARBON', 'MSIMG', 'WINCOMCTL', 'ADVAPI', 'WINSHELL', 'X11', 'PNG'])
TargetAdd('p3dembed.exe', opts=['NOICON', 'WINGDI', 'WINSOCK2', 'ZLIB', 'WINUSER', 'OPENSSL', 'WINOLE', 'CARBON', 'MSIMG', 'WINCOMCTL', 'ADVAPI', 'WINSHELL', 'X11'])
if GetTarget() == 'windows':
OPTS.append("P3DEMBEDW")
@ -5033,7 +5030,7 @@ if (RTDIST):
TargetAdd('p3dembedw.exe', input='plugin_common.obj')
TargetAdd('p3dembedw.exe', input='libp3tinyxml.ilb')
TargetAdd('p3dembedw.exe', input='libp3d_plugin_static.ilb')
TargetAdd('p3dembedw.exe', opts=['NOICON', 'WINGDI', 'WINSOCK2', 'ZLIB', 'WINUSER', 'OPENSSL', 'JPEG', 'WINOLE', 'MSIMG', 'WINCOMCTL', 'ADVAPI', 'WINSHELL', 'PNG'])
TargetAdd('p3dembedw.exe', opts=['NOICON', 'WINGDI', 'WINSOCK2', 'ZLIB', 'WINUSER', 'OPENSSL', 'WINOLE', 'MSIMG', 'WINCOMCTL', 'ADVAPI', 'WINSHELL'])
#
# DIRECTORY: pandatool/src/pandatoolbase/

View File

@ -1534,8 +1534,9 @@ def SmartPkgEnable(pkg, pkgconfig = None, libs = None, incs = None, defs = None,
if (have_all_pkgs):
return
if (pkgconfig != None and (libs == None or len(libs) == 0)):
if (pkg in PkgListGet()):
if pkgconfig is not None and not libs and not incs:
# pkg-config is all we can do, abort if it wasn't found.
if pkg in PkgListGet():
print("%sWARNING:%s Could not locate pkg-config package %s, excluding from build" % (GetColor("red"), GetColor(), pkgconfig))
PkgDisable(pkg)
else: