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);


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/