Re: [AD] [ alleg-Bugs-2121233 ] JPEG loader |
[ Thread Index |
Date Index
| More lists.liballeg.org/allegro-developers Archives
]
On Mon, 2008-09-22 at 14:18 +0000, SourceForge.net wrote:
>
> Message:
> I have a libjpeg addon for A4, will try adding that.
>
Attached (scons build only so far). Saving is implemented but completely
untested, so likely needs some fixes before it works.
This also hit an old problem - what if bitmaps are bigger than the
maximum supported texture size of a display? In my case my camera makes
jpgs which are bigger than the max texture size of my OpenGL drivers, so
the problem is quite apparent with any jpg i have :/
I hacked ex_bitmap to use memory bitmaps if it can't use display
bitmaps.. so at least I can view my jpgs now.
--
Elias Pschernig <elias@xxxxxxxxxx>
Index: scons/helpers.py
===================================================================
--- scons/helpers.py (revision 10928)
+++ scons/helpers.py (working copy)
@@ -12,17 +12,20 @@
def __init__( self ):
self.hash = dict()
- def __getitem__( self, key ):
+ def __getitem__(self, key):
try:
return self.hash[ key ]
except KeyError:
return False
- def __setitem__( self, key, value ):
+ def __setitem__(self, key, value):
self.hash[ key ] = value
- def keys( self ):
+ def keys(self):
return self.hash.keys()
+
+ def __str__(self):
+ return str(self.hash)
# Global state to handle configuration things
configure_state = SimpleHash()
@@ -105,7 +108,7 @@
line = re.sub(r"\$\{(.*?)\}", substitute_variable, line)
m = re.compile('^#cmakedefine (.*)').match(line)
if m:
- name = m.group(1)
+ name = m.group(1).strip()
if defines[name]:
return "#define %s\n" % name
else:
Index: addons/iio/iio.c
===================================================================
--- addons/iio/iio.c (revision 10927)
+++ addons/iio/iio.c (working copy)
@@ -39,6 +39,9 @@
#ifdef ALLEGRO_CFG_IIO_HAVE_PNG
success |= al_iio_add_handler("png", iio_load_png, iio_save_png);
#endif
+#ifdef ALLEGRO_CFG_IIO_HAVE_JPG
+ success |= al_iio_add_handler("jpg", iio_load_jpg, iio_save_jpg);
+#endif
if (success)
inited = true;
Index: addons/iio/jpg.c
===================================================================
--- addons/iio/jpg.c (revision 0)
+++ addons/iio/jpg.c (revision 0)
@@ -0,0 +1,280 @@
+/* loadpng, Allegro wrapper routines for libpng
+ * by Peter Wang (tjaden@xxxxxxxxxx).
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <jpeglib.h>
+#include <jerror.h>
+
+#include "allegro5/allegro5.h"
+#include "allegro5/internal/aintern_memory.h"
+#include "allegro5/internal/aintern_bitmap.h"
+
+#include "iio.h"
+
+#define BUFFER_SIZE 4096
+
+struct my_src_mgr
+{
+ struct jpeg_source_mgr pub;
+ unsigned char *buffer;
+ PACKFILE *pf;
+};
+
+struct my_dest_mgr
+{
+ struct jpeg_destination_mgr pub;
+ unsigned char *buffer;
+ PACKFILE *pf;
+};
+
+static void init_source(j_decompress_ptr cinfo)
+{
+}
+
+static void init_destination(j_compress_ptr cinfo)
+{
+ struct my_dest_mgr *dest = (void *)cinfo->dest;
+ dest->pub.next_output_byte = dest->buffer;
+ dest->pub.free_in_buffer = BUFFER_SIZE;
+}
+
+static int fill_input_buffer(j_decompress_ptr cinfo)
+{
+ struct my_src_mgr *src = (void *)cinfo->src;
+ src->pub.next_input_byte = src->buffer;
+ src->pub.bytes_in_buffer = pack_fread(src->buffer, BUFFER_SIZE,
+ src->pf);
+ return 1;
+}
+
+static int empty_output_buffer(j_compress_ptr cinfo)
+{
+ struct my_dest_mgr *dest = (void *)cinfo->dest;
+ pack_fwrite(dest->buffer, BUFFER_SIZE, dest->pf);
+ dest->pub.next_output_byte = dest->buffer;
+ dest->pub.free_in_buffer = BUFFER_SIZE;
+ return 1;
+}
+
+static void skip_input_data(j_decompress_ptr cinfo, long num_bytes)
+{
+ struct my_src_mgr *src = (void *)cinfo->src;
+ if (num_bytes <= src->pub.bytes_in_buffer) {
+ src->pub.next_input_byte += num_bytes;
+ src->pub.bytes_in_buffer -= num_bytes;
+ }
+ else {
+ long skip = num_bytes - src->pub.bytes_in_buffer;
+ pack_fseek(src->pf, skip);
+ src->pub.bytes_in_buffer = 0;
+ }
+}
+
+static void term_source(j_decompress_ptr cinfo)
+{
+}
+
+static void term_destination(j_compress_ptr cinfo)
+{
+ struct my_dest_mgr *dest = (void *)cinfo->dest;
+ pack_fwrite(dest->buffer, BUFFER_SIZE - dest->pub.free_in_buffer,
+ dest->pf);
+}
+
+
+static void jpeg_packfile_src(j_decompress_ptr cinfo, PACKFILE *pf,
+ unsigned char *buffer)
+{
+ struct my_src_mgr *src;
+
+ if (!cinfo->src)
+ cinfo->src = (*cinfo->mem->alloc_small)((void *)cinfo, JPOOL_PERMANENT,
+ sizeof *src);
+
+ src = (void *)cinfo->src;
+ src->pub.init_source = init_source;
+ src->pub.fill_input_buffer = fill_input_buffer;
+ src->pub.skip_input_data = skip_input_data;
+ src->pub.resync_to_restart = jpeg_resync_to_restart;
+ src->pub.term_source = term_source;
+ src->pub.bytes_in_buffer = 0;
+ src->buffer = buffer;
+ src->pf = pf;
+}
+
+static void jpeg_packfile_dest(j_compress_ptr cinfo, PACKFILE *pf,
+ unsigned char *buffer)
+{
+ struct my_dest_mgr *dest;
+
+ if (!cinfo->dest)
+ cinfo->dest = (*cinfo->mem->alloc_small)((void *)cinfo, JPOOL_PERMANENT,
+ sizeof *dest);
+
+ dest = (void *)cinfo->dest;
+ dest->pub.init_destination = init_destination;
+ dest->pub.empty_output_buffer = empty_output_buffer;
+ dest->pub.term_destination = term_destination;
+ dest->pub.free_in_buffer = 0;
+ dest->buffer = buffer;
+ dest->pf = pf;
+}
+
+static ALLEGRO_BITMAP *load_jpg_pf(PACKFILE *pf)
+{
+ struct jpeg_decompress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ ALLEGRO_BITMAP *bmp = NULL;
+ ALLEGRO_LOCKED_REGION lock;
+ ALLEGRO_STATE backup;
+ unsigned char *buffer = NULL;
+ unsigned char *rows[1] = {NULL};
+ int w, h, s;
+
+ cinfo.err = jpeg_std_error(&jerr);
+
+ buffer = _AL_MALLOC(BUFFER_SIZE);
+
+ jpeg_create_decompress(&cinfo);
+ jpeg_packfile_src(&cinfo, pf, buffer);
+ jpeg_read_header(&cinfo, TRUE);
+ jpeg_start_decompress(&cinfo);
+
+ w = cinfo.output_width;
+ h = cinfo.output_height;
+ s = cinfo.output_components;
+
+ /* Only one and three components make sense in a JPG file. */
+ if (s != 1 && s != 3) {
+ goto error;
+ }
+
+ bmp = al_create_bitmap(w, h);
+ al_lock_bitmap(bmp, &lock, ALLEGRO_LOCK_WRITEONLY);
+ al_store_state(&backup, ALLEGRO_STATE_TARGET_BITMAP);
+ al_set_target_bitmap(bmp);
+
+ rows[0] = _AL_MALLOC(w * s);
+
+ while ((int)cinfo.output_scanline < h) {
+ int x, y = cinfo.output_scanline;
+ jpeg_read_scanlines(&cinfo, (void *)rows, 1);
+ for (x = 0; x < w; x++) {
+ if (s == 1) {
+ unsigned char c = rows[0][x];
+ al_put_pixel(x, y, al_map_rgb(c, c, c));
+ }
+ else if (s == 3) {
+ unsigned char r = rows[0][x * s + 0];
+ unsigned char g = rows[0][x * s + 1];
+ unsigned char b = rows[0][x * s + 2];
+ al_put_pixel(x, y, al_map_rgb(r, g, b));
+ }
+ }
+ }
+
+ al_unlock_bitmap(bmp);
+ al_restore_state(&backup);
+
+error:
+ _AL_FREE(buffer);
+ _AL_FREE(rows[0]);
+ jpeg_finish_decompress(&cinfo);
+ jpeg_destroy_decompress(&cinfo);
+
+ return bmp;
+}
+
+static int save_jpg_pf(PACKFILE *pf, ALLEGRO_BITMAP *bmp)
+{
+ struct jpeg_compress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ ALLEGRO_LOCKED_REGION lock;
+ ALLEGRO_STATE backup;
+ unsigned char *buffer = NULL;
+ unsigned char *rows[1] = {NULL};
+
+ cinfo.err = jpeg_std_error(&jerr);
+
+ buffer = _AL_MALLOC(BUFFER_SIZE);
+
+ jpeg_create_compress(&cinfo);
+ jpeg_packfile_dest(&cinfo, pf, buffer);
+
+ cinfo.image_width = al_get_bitmap_width(bmp);
+ cinfo.image_height = al_get_bitmap_height(bmp);
+ cinfo.input_components = 3;
+ cinfo.in_color_space = JCS_RGB;
+ jpeg_set_defaults(&cinfo);
+
+ jpeg_start_compress(&cinfo, 1);
+
+ al_lock_bitmap(bmp, &lock, ALLEGRO_LOCK_READONLY);
+ al_store_state(&backup, ALLEGRO_STATE_TARGET_BITMAP);
+ al_set_target_bitmap(bmp);
+
+ rows[0] = _AL_MALLOC(cinfo.image_width * 3);
+
+ while ((int)cinfo.next_scanline < cinfo.image_height) {
+ int x, y = cinfo.next_scanline;
+ for (x = 0; x < cinfo.image_width; x++) {
+ unsigned char r, g, b;
+ al_unmap_rgb(al_get_pixel(bmp, x, y), &r, &g, &b);
+ rows[0][x * 3 + 0] = r;
+ rows[0][x * 3 + 1] = g;
+ rows[0][x * 3 + 2] = b;
+ }
+ jpeg_write_scanlines(&cinfo, (void *)rows, 1);
+ }
+
+ al_unlock_bitmap(bmp);
+ al_restore_state(&backup);
+
+ _AL_FREE(buffer);
+ _AL_FREE(rows[0]);
+ jpeg_finish_compress(&cinfo);
+ jpeg_destroy_compress(&cinfo);
+
+ return 1;
+}
+
+ALLEGRO_BITMAP *iio_load_jpg(char const *filename)
+{
+ PACKFILE *pf;
+ ALLEGRO_BITMAP *bmp;
+
+ ASSERT(filename);
+
+ pf = pack_fopen(filename, "r");
+ if (!pf)
+ return NULL;
+
+ bmp = load_jpg_pf(pf);
+
+ pack_fclose(pf);
+
+ return bmp;
+}
+
+int iio_save_jpg(char const *filename, ALLEGRO_BITMAP *bmp)
+{
+ PACKFILE *pf;
+ int result;
+
+ ASSERT(filename);
+ ASSERT(bmp);
+
+ pf = pack_fopen(filename, "w");
+ if (!pf) {
+ TRACE("Unable to open file %s for writing\n", filename);
+ return -1;
+ }
+
+ result = save_jpg_pf(pf, bmp);
+
+ pack_fclose(pf);
+
+ return result;
+}
Index: addons/iio/iio.h
===================================================================
--- addons/iio/iio.h (revision 10927)
+++ addons/iio/iio.h (working copy)
@@ -16,12 +16,14 @@
ALLEGRO_BITMAP *iio_load_bmp(AL_CONST char *filename);
ALLEGRO_BITMAP *iio_load_tga(AL_CONST char *filename);
ALLEGRO_BITMAP *iio_load_png(AL_CONST char *filename);
+ALLEGRO_BITMAP *iio_load_jpg(AL_CONST char *filename);
int iio_save_pcx(AL_CONST char *filename, ALLEGRO_BITMAP *bmp);
int iio_save_bmp(AL_CONST char *filename, ALLEGRO_BITMAP *bmp);
int iio_save_tga(AL_CONST char *filename, ALLEGRO_BITMAP *bmp);
int iio_save_png(AL_CONST char *filename, ALLEGRO_BITMAP *bmp);
+int iio_save_jpg(AL_CONST char *filename, ALLEGRO_BITMAP *bmp);
Index: addons/iio/SConscript
===================================================================
--- addons/iio/SConscript (revision 10927)
+++ addons/iio/SConscript (working copy)
@@ -15,23 +15,24 @@
def setupPlatform(settings, config):
settings["ALLEGRO_CFG_IIO_HAVE_PNG"] = config.CheckHeader("png.h") and\
- config.CheckLib("png")
+ config.CheckLib("png")
+ settings["ALLEGRO_CFG_IIO_HAVE_JPG"] = config.CheckHeader(["stdio.h",
+ "stdlib.h", "jpeglib.h"]) and config.CheckLib("jpeg")
return config.Finish()
settings, configure_env = helpers.do_configure('iio', context,
- tests, setupPlatform,
- 'allegro5/internal/aintern_iio_cfg.h.cmake',
- 'allegro5/internal/aintern_iio_cfg.h',
- getArgumentOption('config', 0))
+ tests, setupPlatform,
+ 'allegro5/internal/aintern_iio_cfg.h.cmake',
+ 'allegro5/internal/aintern_iio_cfg.h',
+ getArgumentOption('config', 0))
+env.Append(LIBS = ['png', 'z', 'jpeg'])
-env.Append(LIBS = ['png','z'])
-
result = addons.do_build(
context = context,
env = myEnv,
- source = ["bmp.c", "iio.c", "pcx.c", "tga.c", "png.c"],
- libs = ["png", "z"],
+ source = ["bmp.c", "iio.c", "pcx.c", "tga.c", "png.c", "jpg.c"],
+ libs = ["png", "z", "jpeg"],
dir = "iio",
name = "a5_iio",
install_headers = ["allegro5/a5_iio.h",
Index: addons/iio/allegro5/internal/aintern_iio_cfg.h.cmake
===================================================================
--- addons/iio/allegro5/internal/aintern_iio_cfg.h.cmake (revision 10927)
+++ addons/iio/allegro5/internal/aintern_iio_cfg.h.cmake (working copy)
@@ -1 +1,2 @@
#cmakedefine ALLEGRO_CFG_IIO_HAVE_PNG
+#cmakedefine ALLEGRO_CFG_IIO_HAVE_JPG
Index: examples/ex_bitmap.c
===================================================================
--- examples/ex_bitmap.c (revision 10927)
+++ examples/ex_bitmap.c (working copy)
@@ -5,10 +5,11 @@
{
const char *filename;
ALLEGRO_DISPLAY *display;
- ALLEGRO_BITMAP *bitmap;
+ ALLEGRO_BITMAP *membitmap, *bitmap;
ALLEGRO_TIMER *timer;
ALLEGRO_EVENT_QUEUE *queue;
bool redraw = true;
+ double zoom = 1;
if (argc > 1) {
filename = argv[1];
@@ -34,13 +35,25 @@
}
al_set_window_title(filename);
-
- bitmap = al_iio_load(filename);
+
+ /* We load the bitmap into a memory bitmap, because creating a
+ * display bitmap could fail if the bitmap is too big to fit into a
+ * single texture.
+ * FIXME: Or should A5 automatically created multiple display bitmaps?
+ */
+ al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP);
+ membitmap = al_iio_load(filename);
if (!bitmap) {
TRACE("%s not found or failed to load", filename);
return 1;
}
+ al_set_new_bitmap_flags(0);
+ // FIXME:
+ // Now try to split the memory bitmap into display bitmaps?
+ bitmap = al_clone_bitmap(membitmap);
+ if (!bitmap) bitmap = membitmap;
+
timer = al_install_timer(1.0 / 30);
queue = al_create_event_queue();
al_register_event_source(queue, (ALLEGRO_EVENT_SOURCE *)al_get_keyboard());
@@ -53,16 +66,23 @@
al_wait_for_event(queue, &event);
if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE)
break;
- if (event.type == ALLEGRO_EVENT_KEY_DOWN &&
- event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) {
- break;
+ if (event.type == ALLEGRO_EVENT_KEY_DOWN) {
+ if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
+ break;
+ if (event.keyboard.unichar == '+')
+ zoom *= 1.1;
+ if (event.keyboard.unichar == '-')
+ zoom /= 1.1;
+ if (event.keyboard.unichar == 'f')
+ zoom = 320.0 / al_get_bitmap_width(bitmap);
}
if (event.type == ALLEGRO_EVENT_TIMER)
redraw = true;
if (redraw && al_event_queue_is_empty(queue)) {
redraw = false;
- al_draw_bitmap(bitmap, 0, 0, 0);
+ al_clear(al_map_rgb_f(0, 0, 0));
+ al_draw_rotated_scaled_bitmap(bitmap, 0, 0, 0, 0, zoom, zoom, 0, 0);
al_flip_display();
}
}
Index: src/opengl/ogl_bitmap.c
===================================================================
--- src/opengl/ogl_bitmap.c (revision 10927)
+++ src/opengl/ogl_bitmap.c (working copy)
@@ -276,6 +276,11 @@
if (glGetError()) {
TRACE("ogl_bitmap: glTexImage2D for format %d, size %dx%d failed\n",
bitmap->format, ogl_bitmap->true_w, ogl_bitmap->true_h);
+ glDeleteTextures(1, &ogl_bitmap->texture);
+ ogl_bitmap->texture = 0;
+ // FIXME: Should we convert it into a memory bitmap? Or if the size is
+ // the problem try to use multiple textures?
+ return false;
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);