summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/rendutil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/rendutil.cpp')
-rw-r--r--src/emu/rendutil.cpp319
1 files changed, 221 insertions, 98 deletions
diff --git a/src/emu/rendutil.cpp b/src/emu/rendutil.cpp
index 18755ffb340..64887d111bd 100644
--- a/src/emu/rendutil.cpp
+++ b/src/emu/rendutil.cpp
@@ -11,9 +11,109 @@
#include "emu.h"
#include "rendutil.h"
+#include "msdib.h"
#include "png.h"
#include "jpeglib.h"
+#include "jerror.h"
+
+
+namespace {
+
+struct jpeg_corefile_source : public jpeg_source_mgr
+{
+ static void source(j_decompress_ptr cinfo, util::core_file &file);
+
+private:
+ static constexpr unsigned INPUT_BUF_SIZE = 4096;
+
+ static void do_init(j_decompress_ptr cinfo)
+ {
+ jpeg_corefile_source &src = *static_cast<jpeg_corefile_source *>(cinfo->src);
+ src.start_of_file = true;
+ }
+
+ static boolean do_fill(j_decompress_ptr cinfo)
+ {
+ jpeg_corefile_source &src = *static_cast<jpeg_corefile_source *>(cinfo->src);
+
+ size_t nbytes = src.infile->read(src.buffer, INPUT_BUF_SIZE);
+
+ if (0 >= nbytes)
+ {
+ if (src.start_of_file)
+ ERREXIT(cinfo, JERR_INPUT_EMPTY);
+ WARNMS(cinfo, JWRN_JPEG_EOF);
+ src.buffer[0] = JOCTET(0xff);
+ src.buffer[1] = JOCTET(JPEG_EOI);
+ nbytes = 2;
+ }
+
+ src.next_input_byte = src.buffer;
+ src.bytes_in_buffer = nbytes;
+ src.start_of_file = false;
+
+ return TRUE;
+ }
+
+ static void do_skip(j_decompress_ptr cinfo, long num_bytes)
+ {
+ jpeg_corefile_source &src = *static_cast<jpeg_corefile_source *>(cinfo->src);
+
+ if (0 < num_bytes)
+ {
+ while (long(src.bytes_in_buffer) < num_bytes)
+ {
+ num_bytes -= long(src.bytes_in_buffer);
+ (void)(*src.fill_input_buffer)(cinfo);
+ }
+ src.next_input_byte += size_t(num_bytes);
+ src.bytes_in_buffer -= size_t(num_bytes);
+ }
+ }
+
+ static void do_term(j_decompress_ptr cinfo)
+ {
+ }
+
+ util::core_file *infile;
+ JOCTET *buffer;
+ bool start_of_file;
+};
+
+void jpeg_corefile_source::source(j_decompress_ptr cinfo, util::core_file &file)
+{
+ jpeg_corefile_source *src;
+ if (!cinfo->src)
+ {
+ src = reinterpret_cast<jpeg_corefile_source *>(
+ (*cinfo->mem->alloc_small)(
+ reinterpret_cast<j_common_ptr>(cinfo),
+ JPOOL_PERMANENT,
+ sizeof(jpeg_corefile_source)));
+ cinfo->src = src;
+ src->buffer = reinterpret_cast<JOCTET *>(
+ (*cinfo->mem->alloc_small)(
+ reinterpret_cast<j_common_ptr>(cinfo),
+ JPOOL_PERMANENT,
+ INPUT_BUF_SIZE * sizeof(JOCTET)));
+ }
+ else
+ {
+ src = static_cast<jpeg_corefile_source *>(cinfo->src);
+ }
+
+ src->init_source = &jpeg_corefile_source::do_init;
+ src->fill_input_buffer = &jpeg_corefile_source::do_fill;
+ src->skip_input_data = &jpeg_corefile_source::do_skip;
+ src->resync_to_restart = jpeg_resync_to_restart;
+ src->term_source = &jpeg_corefile_source::do_term;
+ src->infile = &file;
+ src->bytes_in_buffer = 0;
+ src->next_input_byte = nullptr;
+}
+
+} // anonymous namespace
/***************************************************************************
@@ -23,7 +123,7 @@
/* utilities */
static void resample_argb_bitmap_average(u32 *dest, u32 drowpixels, u32 dwidth, u32 dheight, const u32 *source, u32 srowpixels, u32 swidth, u32 sheight, const render_color &color, u32 dx, u32 dy);
static void resample_argb_bitmap_bilinear(u32 *dest, u32 drowpixels, u32 dwidth, u32 dheight, const u32 *source, u32 srowpixels, u32 swidth, u32 sheight, const render_color &color, u32 dx, u32 dy);
-static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const png_info &png);
+static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const util::png_info &png);
@@ -543,81 +643,103 @@ void render_line_to_quad(const render_bounds *bounds, float width, float length_
/*-------------------------------------------------
- render_load_jpeg - load a JPG file into a
- bitmap
+ render_load_msdib - load a Microsoft DIB file
+ into a bitmap
-------------------------------------------------*/
-void render_load_jpeg(bitmap_argb32 &bitmap, emu_file &file, const char *dirname, const char *filename)
+void render_load_msdib(bitmap_argb32 &bitmap, util::core_file &file)
{
// deallocate previous bitmap
bitmap.reset();
- // define file's full name
- std::string fname;
+ // read the DIB data
+ util::msdib_error const result = util::msdib_read_bitmap(file, bitmap);
+ if (result != util::msdib_error::NONE)
+ {
+ osd_printf_error("Error reading Microsoft DIB file\n");
+ bitmap.reset();
+ }
+}
- if (dirname == nullptr)
- fname = filename;
- else
- fname.assign(dirname).append(PATH_SEPARATOR).append(filename);
- if (file.open(fname) != osd_file::error::NONE)
- return;
+/*-------------------------------------------------
+ render_load_jpeg - load a JPEG file into a
+ bitmap
+-------------------------------------------------*/
+
+void render_load_jpeg(bitmap_argb32 &bitmap, util::core_file &file)
+{
+ // deallocate previous bitmap
+ bitmap.reset();
- // define standard JPEG structures
+ // create a JPEG source for the file
jpeg_decompress_struct cinfo;
jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
- jpeg_create_decompress(&cinfo);
-
- // allocates a buffer for the image
- u32 jpg_size = file.size();
- std::unique_ptr<unsigned char[]> jpg_buffer = std::make_unique<unsigned char[]>(jpg_size);
-
- // read data from the file and set them in the buffer
- file.read(jpg_buffer.get(), jpg_size);
- jpeg_mem_src(&cinfo, jpg_buffer.get(), jpg_size);
-
- // read JPEG header and start decompression
- jpeg_read_header(&cinfo, TRUE);
- jpeg_start_decompress(&cinfo);
-
- // allocates the destination bitmap
- int w = cinfo.output_width;
- int h = cinfo.output_height;
- int s = cinfo.output_components;
- bitmap.allocate(w, h);
-
- // allocates a buffer to receive the information and copy them into the bitmap
- int row_stride = cinfo.output_width * cinfo.output_components;
- JSAMPARRAY buffer = (JSAMPARRAY)malloc(sizeof(JSAMPROW));
- buffer[0] = (JSAMPROW)malloc(sizeof(JSAMPLE) * row_stride);
-
- while ( cinfo.output_scanline < cinfo.output_height )
+ jerr.error_exit = [] (j_common_ptr cinfo) { throw cinfo->err; };
+ JSAMPARRAY buffer = nullptr;
+ try
{
- int j = cinfo.output_scanline;
- jpeg_read_scanlines(&cinfo, buffer, 1);
+ jpeg_create_decompress(&cinfo);
+ cinfo.mem->max_memory_to_use = 128 * 1024 * 1024;
+ jpeg_corefile_source::source(&cinfo, file);
+
+ // read JPEG header and start decompression
+ jpeg_read_header(&cinfo, TRUE);
+ jpeg_start_decompress(&cinfo);
+
+ // allocates the destination bitmap
+ int w = cinfo.output_width;
+ int h = cinfo.output_height;
+ int s = cinfo.output_components;
+ bitmap.allocate(w, h);
+
+ // allocates a buffer to receive the information and copy them into the bitmap
+ int row_stride = cinfo.output_width * cinfo.output_components;
+ JSAMPARRAY buffer = reinterpret_cast<JSAMPARRAY>(malloc(sizeof(JSAMPROW)));
+ buffer[0] = reinterpret_cast<JSAMPROW>(malloc(sizeof(JSAMPLE) * row_stride));
+
+ while (cinfo.output_scanline < cinfo.output_height)
+ {
+ int j = cinfo.output_scanline;
+ jpeg_read_scanlines(&cinfo, buffer, 1);
- if (s == 1)
- for (int i = 0; i < w; ++i)
- bitmap.pix(j, i) = rgb_t(0xFF, buffer[0][i], buffer[0][i], buffer[0][i]);
+ if (s == 1)
+ {
+ for (int i = 0; i < w; ++i)
+ bitmap.pix(j, i) = rgb_t(0xFF, buffer[0][i], buffer[0][i], buffer[0][i]);
- else if (s == 3)
- for (int i = 0; i < w; ++i)
- bitmap.pix(j, i) = rgb_t(0xFF, buffer[0][i * s], buffer[0][i * s + 1], buffer[0][i * s + 2]);
- else
- {
- osd_printf_error("Cannot read JPEG data from %s file.\n", fname);
- bitmap.reset();
- break;
+ }
+ else if (s == 3)
+ {
+ for (int i = 0; i < w; ++i)
+ bitmap.pix(j, i) = rgb_t(0xFF, buffer[0][i * s], buffer[0][i * s + 1], buffer[0][i * s + 2]);
+ }
+ else
+ {
+ osd_printf_error("Cannot read JPEG data from file.\n");
+ bitmap.reset();
+ break;
+ }
}
- }
- // finish decompression and frees the memory
- jpeg_finish_decompress(&cinfo);
+ // finish decompression and frees the memory
+ jpeg_finish_decompress(&cinfo);
+ }
+ catch (jpeg_error_mgr *)
+ {
+ char msg[1024];
+ (cinfo.err->format_message)(reinterpret_cast<j_common_ptr>(&cinfo), msg);
+ osd_printf_error("JPEG error reading data from file: %s\n", msg);
+ bitmap.reset();
+ }
jpeg_destroy_decompress(&cinfo);
- file.close();
- free(buffer[0]);
- free(buffer);
+ if (buffer)
+ {
+ if (buffer[0])
+ free(buffer[0]);
+ free(buffer);
+ }
}
@@ -626,36 +748,25 @@ void render_load_jpeg(bitmap_argb32 &bitmap, emu_file &file, const char *dirname
bitmap
-------------------------------------------------*/
-bool render_load_png(bitmap_argb32 &bitmap, emu_file &file, const char *dirname, const char *filename, bool load_as_alpha_to_existing)
+bool render_load_png(bitmap_argb32 &bitmap, util::core_file &file, bool load_as_alpha_to_existing)
{
// deallocate if we're not overlaying alpha
if (!load_as_alpha_to_existing)
bitmap.reset();
- // open the file
- std::string fname;
- if (dirname)
- fname.assign(dirname).append(PATH_SEPARATOR).append(filename);
- else
- fname.assign(filename);
- osd_file::error const filerr = file.open(fname);
- if (filerr != osd_file::error::NONE)
- return false;
-
// read the PNG data
- png_info png;
- png_error const result = png.read_file(file);
- file.close();
- if (result != PNGERR_NONE)
+ util::png_info png;
+ util::png_error const result = png.read_file(file);
+ if (result != util::png_error::NONE)
{
- osd_printf_error("%s: Error reading PNG file\n", filename);
+ osd_printf_error("Error reading PNG file\n");
return false;
}
// if less than 8 bits, upsample
- if (PNGERR_NONE != png.expand_buffer_8bit())
+ if (util::png_error::NONE != png.expand_buffer_8bit())
{
- osd_printf_error("%s: Error upsampling PNG bitmap\n", filename);
+ osd_printf_error("Error upsampling PNG bitmap\n");
return false;
}
@@ -663,9 +774,9 @@ bool render_load_png(bitmap_argb32 &bitmap, emu_file &file, const char *dirname,
if (!load_as_alpha_to_existing)
{
// non-alpha case
- if (PNGERR_NONE != png.copy_to_bitmap(bitmap, hasalpha))
+ if (util::png_error::NONE != png.copy_to_bitmap(bitmap, hasalpha))
{
- osd_printf_error("%s: Error copying PNG bitmap to MAME bitmap\n", filename);
+ osd_printf_error("Error copying PNG bitmap to MAME bitmap\n");
return false;
}
}
@@ -674,7 +785,7 @@ bool render_load_png(bitmap_argb32 &bitmap, emu_file &file, const char *dirname,
// verify we can handle this PNG
if (png.bit_depth > 8)
{
- osd_printf_error("%s: Unsupported bit depth %d (8 bit max)\n", filename, png.bit_depth);
+ osd_printf_error("Unsupported bit depth %d (8 bit max)\n", png.bit_depth);
return false;
}
@@ -692,7 +803,7 @@ bool render_load_png(bitmap_argb32 &bitmap, emu_file &file, const char *dirname,
to the alpha channel of a bitmap
-------------------------------------------------*/
-static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const png_info &png)
+static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const util::png_info &png)
{
// FIXME: this function is basically copy/pasted from the PNG code in util, and should be unified with it
u8 accumalpha = 0xff;
@@ -803,29 +914,41 @@ static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const png_info &png)
render_detect_image - detect image format
-------------------------------------------------*/
-ru_imgformat render_detect_image(emu_file &file, const char *dirname, const char *filename)
+ru_imgformat render_detect_image(util::core_file &file)
{
- // open the file
- std::string fname;
- if (dirname)
- fname.assign(dirname).append(PATH_SEPARATOR).append(filename);
- else
- fname.assign(filename);
- osd_file::error const filerr = file.open(fname);
- if (filerr != osd_file::error::NONE)
- return RENDUTIL_IMGFORMAT_ERROR;
-
// PNG: check for valid header
- png_error const result = png_info::verify_header(file);
- if (result == PNGERR_NONE)
- {
- file.close();
+ util::png_error const png = util::png_info::verify_header(file);
+ file.seek(0, SEEK_SET);
+ if (util::png_error::NONE == png)
return RENDUTIL_IMGFORMAT_PNG;
- }
+ // JPEG: attempt to read header with libjpeg
+ jpeg_decompress_struct cinfo;
+ jpeg_error_mgr jerr;
+ cinfo.err = jpeg_std_error(&jerr);
+ jerr.error_exit = [] (j_common_ptr cinfo) { throw cinfo->err; };
+ try
+ {
+ jpeg_create_decompress(&cinfo);
+ cinfo.mem->max_memory_to_use = 128 * 1024 * 1024;
+ jpeg_corefile_source::source(&cinfo, file);
+ jpeg_read_header(&cinfo, TRUE);
+ jpeg_destroy_decompress(&cinfo);
+ file.seek(0, SEEK_SET);
+ return RENDUTIL_IMGFORMAT_JPEG;
+ }
+ catch (jpeg_error_mgr *)
+ {
+ jpeg_destroy_decompress(&cinfo);
+ file.seek(0, SEEK_SET);
+ }
+
+ // Microsoft DIB: check for valid header
+ util::msdib_error const msdib = util::msdib_verify_header(file);
file.seek(0, SEEK_SET);
- // TODO: add more when needed
+ if (util::msdib_error::NONE == msdib)
+ return RENDUTIL_IMGFORMAT_MSDIB;
- file.close();
+ // TODO: add more as necessary
return RENDUTIL_IMGFORMAT_UNKNOWN;
}