Index: apps/metadata.c
===================================================================
RCS file: /cvsroot/rockbox/apps/metadata.c,v
retrieving revision 1.42
diff -u -r1.42 metadata.c
--- rockbox/apps/metadata.c	11 Apr 2006 03:54:24 -0000	1.42
+++ apps/metadata.c	12 Apr 2006 12:56:23 -0000
@@ -29,6 +29,7 @@
 #include "replaygain.h"
 #include "debug.h"
 #include "system.h"
+#include "gwps.h"
 
 enum tagtype { TAGTYPE_APE = 1, TAGTYPE_VORBIS };
 
@@ -1413,11 +1414,114 @@
     return AFMT_UNKNOWN;
 }
 
+/* Strip filename from a full path
+ *
+ * buf      - buffer to extract directory to.
+ * buf_size - size of buffer.
+ * fullpath  - fullpath to extract from.
+ *
+ * Returns the full path to the file, minus the file name (including the last slash).
+ */
+static char* strip_filename(char* buf, int buf_size, const char* fullpath)
+{
+    char* sep;
+    int len;
+
+    if (!buf || buf_size <= 0 || !fullpath)
+        return NULL;
+
+    buf[0] = 0;
+
+    /* if 'fullpath' is not a full path, but only a filename, return immediately */
+    sep = strrchr(fullpath,'/');
+    if (sep == NULL)
+        return NULL;
+
+    len = MIN(sep - fullpath + 1, buf_size - 1);
+    strncpy(buf, fullpath, len);
+    buf[len] = 0;
+    return buf;
+}
+
+static char* strip_extension(char* buf, int buf_size, const char* file)
+{
+    char* sep;
+    int len;
+
+    if (!buf || buf_size <= 0 || !file)
+        return NULL;
+
+    buf[0] = 0;
+
+    sep = strrchr(file,'.');
+    if (sep == NULL)
+        return NULL;
+
+    len = MIN(sep - file, buf_size - 1);
+    strncpy(buf, file, len);
+    buf[len] = 0;
+    return buf;
+}
+
+static bool file_exists(char *file)
+{
+    int fd;
+
+    if (!file || strlen(file) <= 0)
+        return false;
+
+    fd = open(file, O_RDONLY);
+    if (fd<0)
+        return false;
+    close(fd);
+    return true;
+}
+
+/* Look for album art in the same dir as the track.
+ * Returns true if an album art was found, false otherwise */
+static bool find_albumart(struct track_info* track, const char* trackname)
+{
+    char path[MAX_PATH+1];
+
+    if (!track || !trackname)
+        return false;
+
+    strip_extension(path, sizeof(path) - 4, trackname);
+    strcat(path, ".bmp");           /* the first file we look for is one specific to the track playing */
+    if (!file_exists(path))         /* if it doesn't exist, we look for a file specific to the track's album name */
+    {
+        char dir[MAX_PATH+1];
+        strip_filename(dir, sizeof(dir), trackname);
+        if (track->id3.album && strlen(track->id3.album) > 0)
+        {
+            snprintf(path, sizeof(path)-1,
+                     "%s%s.bmp",
+                     (strlen(dir) >= 1) ? dir : "",
+                     track->id3.album);
+            path[sizeof(path)-1] = 0;
+        }
+
+        if (!file_exists(path))         /* if it still doesn't exist, we look for a generic file */
+        {
+            snprintf(path, sizeof(path)-1,
+                     "%scover.bmp",
+                     (strlen(dir) >= 1) ? dir : "");
+            path[sizeof(path)-1] = 0;
+            if (!file_exists(path))
+                return false;
+        }
+    }
+
+    strcpy(track->id3.albumart_path, path);
+    DEBUGF("Album art found for %s : %s\n", trackname, path);
+    return true;
+}
+
 /* Get metadata for track - return false if parsing showed problems with the
  * file that would prevent playback.
  */
 bool get_metadata(struct track_info* track, int fd, const char* trackname,
-    bool v1first) 
+                  bool v1first, bool search_album_art)
 {
 #if CONFIG_CODEC == SWCODEC
     unsigned char* buf;
@@ -1619,10 +1723,14 @@
 
     /* We have successfully read the metadata from the file */
 
+    if (search_album_art && gui_sync_wps_has_albumart())
+    {
+        track->id3.albumart_found = find_albumart(track, trackname);
+    }
+
     lseek(fd, 0, SEEK_SET);
     strncpy(track->id3.path, trackname, sizeof(track->id3.path));
     track->taginfo_ready = true;
 
     return true;
 }
-
Index: apps/metadata.h
===================================================================
RCS file: /cvsroot/rockbox/apps/metadata.h,v
retrieving revision 1.4
diff -u -r1.4 metadata.h
--- rockbox/apps/metadata.h	26 Mar 2006 11:33:41 -0000	1.4
+++ apps/metadata.h	12 Apr 2006 12:56:23 -0000
@@ -24,7 +24,7 @@
 
 unsigned int probe_file_format(const char *filename);
 bool get_metadata(struct track_info* track, int fd, const char* trackname,
-                  bool v1first);
+                  bool v1first, bool search_album_art);
 
 #endif
 
Index: apps/playback.c
===================================================================
RCS file: /cvsroot/rockbox/apps/playback.c,v
retrieving revision 1.262
diff -u -r1.262 playback.c
--- rockbox/apps/playback.c	12 Apr 2006 03:25:54 -0000	1.262
+++ apps/playback.c	12 Apr 2006 12:56:23 -0000
@@ -1694,7 +1694,7 @@
     if (fd < 0)
         return false;
 
-    status = get_metadata(&tracks[next_idx],fd,trackname,v1first);
+    status = get_metadata(&tracks[next_idx],fd,trackname,v1first,true);
     /* Preload the glyphs in the tags */
     if (status) {
         if (tracks[next_idx].id3.title)
@@ -1777,10 +1777,10 @@
 
     /* Get track metadata if we don't already have it. */
     if (!tracks[track_widx].taginfo_ready) 
     {
-        if (get_metadata(&tracks[track_widx],current_fd,trackname,v1first))
+        if (get_metadata(&tracks[track_widx],current_fd,trackname,v1first,true)) 
          {
             if (start_play) 
             {
                 track_changed = true;
                 playlist_update_resume_info(audio_current_track());
@@ -2951,4 +2951,3 @@
 
     queue_post(&audio_queue, Q_AUDIO_POSTINIT, 0);
 }
-
Index: apps/tagcache.c
===================================================================
RCS file: /cvsroot/rockbox/apps/tagcache.c,v
retrieving revision 1.17
diff -u -r1.17 tagcache.c
--- rockbox/apps/tagcache.c	12 Apr 2006 10:31:24 -0000	1.17
+++ apps/tagcache.c	12 Apr 2006 12:56:24 -0000
@@ -1170,7 +1170,7 @@
     memset(&track, 0, sizeof(struct track_info));
     memset(&entry, 0, sizeof(struct temp_file_entry));
     memset(&tracknumfix, 0, sizeof(tracknumfix));
-    ret = get_metadata(&track, fd, path, false);
+    ret = get_metadata(&track, fd, path, false, false);
     close(fd);
 
     if (!ret)
Index: apps/gui/gwps-common.c
===================================================================
RCS file: /cvsroot/rockbox/apps/gui/gwps-common.c,v
retrieving revision 1.50
diff -u -r1.50 gwps-common.c
--- rockbox/apps/gui/gwps-common.c	6 Apr 2006 04:07:06 -0000	1.50
+++ apps/gui/gwps-common.c	12 Apr 2006 12:56:25 -0000
@@ -63,6 +63,10 @@
                                 /* 3% of 30min file == 54s step size */
 #define MIN_FF_REWIND_STEP 500
 
+static char cur_displayed_albumart_path[MAX_PATH] = { "" };
+static int cur_displayed_albumart_width = -1;
+static int cur_displayed_albumart_height = -1;
+
 /* Skip leading UTF-8 BOM, if present. */
 static char* skip_utf8_bom(char* buf)
 {
@@ -99,6 +103,7 @@
  * %xl   -   preload image
  * %we   -   enable statusbar on wps regardless of the global setting
  * %wd   -   disable statusbar on wps regardless of the global setting
+ * %C    -   display a cover bitmap at given position
  * and also for:
  * #     -   a comment line
  *
@@ -176,6 +181,83 @@
         break;
 #endif
 
+        case 'C':
+            /* Album cover */
+            /* format: %C|x|y|[maxwidth|maxheight|] */
+            /* format: %C|x|y|[[+|-]maxwidth|[+|-]maxheight|] */
+        {
+            char *pos = buf+1;
+
+            /* get x-position */
+            pos = strchr(pos, '|');
+            if (!pos)
+                return false;
+            data->albumart_x = atoi(++pos);
+
+            /* get y-position */
+            pos = strchr(pos, '|');
+            if (!pos)
+                return false;
+            data->albumart_y = atoi(++pos);
+
+            /* default max width and height are set to -1 (don't use it) */
+            data->albumart_max_width = -1;
+            data->albumart_max_height = -1;
+            data->albumart_xalign = -1;
+            data->albumart_yalign = -1;
+
+            /* the next fields are optional... */
+            /* get max width */
+            pos = strchr(pos, '|');
+            if (pos)
+            {
+                ++pos;
+                data->albumart_xalign = WPS_ALIGN_CENTER;
+                if (*pos == '-' || *pos == '+')
+                {
+                    if (*pos == '-')
+                        data->albumart_xalign = WPS_ALIGN_RIGHT;
+                    else
+                        data->albumart_xalign = WPS_ALIGN_LEFT;
+                    ++pos;
+                }
+
+                data->albumart_max_width = atoi(pos);
+                if (data->albumart_max_width > LCD_WIDTH)
+                    data->albumart_max_width = LCD_WIDTH;
+                else
+                if (data->albumart_max_width <= 0)
+                    data->albumart_max_width = -1;
+
+                pos = strchr(pos, '|');
+                if (pos)
+                {
+                    ++pos;
+                    data->albumart_yalign = WPS_ALIGN_CENTER;
+                    if (*pos == '-' || *pos == '+')
+                    {
+                        if (*pos == '-')
+                            data->albumart_yalign = WPS_ALIGN_RIGHT;
+                        else
+                            data->albumart_yalign = WPS_ALIGN_LEFT;
+                        ++pos;
+                    }
+
+                    data->albumart_max_height = atoi(pos);
+                    if (data->albumart_max_height > LCD_HEIGHT)
+                        data->albumart_max_height = LCD_HEIGHT;
+                    else
+                    if (data->albumart_max_height <= 0)
+                        data->albumart_max_height = -1;
+                }
+            }
+
+            data->wps_has_albumart = true;
+            return true;
+        }
+
+        break;
+
         case 'P':
             /* progress bar image */
         {
@@ -433,7 +515,7 @@
 
 /* Get the tag specified by the two characters at fmt.
  *
- * cid3      - ID3 data to get tag values from.
+ * cid3     - ID3 data to get tag values from.
  * nid3     - next-song ID3 data to get tag values from.
  * tag      - string (of two characters) specifying the tag to get.
  * buf      - buffer to certain tags, such as track number, play time or
@@ -1098,6 +1152,18 @@
            }
            break;
 #endif
+
+        case 'C':   /* Album cover */
+        {
+            *flags |= WPS_REFRESH_DYNAMIC;
+            if (tag[1] == 'n') /* next track */
+                id3 = nid3;
+
+            if (id3 && id3->albumart_found)
+                return "C";
+            else
+                return NULL;
+        } break;
     }
     return NULL;
 }
@@ -1570,6 +1664,70 @@
                 wps_draw_image(gwps, n);
         }
     }
+
+    /* display album art only if the wps has a tag for it, */
+    /* AND if it's smaller than the max size given in the WPS tags (if given). */
+    /* There is no need to check the bitmap is smaller than the screen, */
+    /* because if it's bigger, it won't have been loaded */
+    if (data->wps_has_albumart
+        && gwps->state->id3->albumart_data != NULL
+        && (data->albumart_max_width < 0
+        || gwps->state->id3->albumart_width <= (unsigned)data->albumart_max_width)
+        && (data->albumart_max_height < 0 
+        || gwps->state->id3->albumart_height <= (unsigned)data->albumart_max_height))
+    {
+        /* coordinates where the cover will be drawn */
+        int x = data->albumart_x;
+        int y = data->albumart_y;
+
+        /* if a bounding box was defined,
+        **   position the cover art either centered, left or right
+        **     to the margins of the box
+        ** otherwise, just draw at the normal coordinate
+        */
+        if (data->albumart_max_width > 0)
+        {
+            switch (data->albumart_xalign)
+            {
+                case WPS_ALIGN_LEFT:
+                    ;
+                break;
+
+                case WPS_ALIGN_RIGHT:
+                    x += data->albumart_max_width - gwps->state->id3->albumart_width;
+                break;
+
+                default: /* WPS_ALIGN_CENTER */
+                    x += (data->albumart_max_width - gwps->state->id3->albumart_width)/2;
+                break;
+            }
+        }
+        if (data->albumart_max_height > 0)
+        {
+            switch (data->albumart_yalign)
+            {
+                case WPS_ALIGN_LEFT:
+                    ;
+                break;
+
+                case WPS_ALIGN_RIGHT:
+                    y += data->albumart_max_height - gwps->state->id3->albumart_height;
+                break;
+
+                default: /* WPS_ALIGN_CENTER */
+                    y += (data->albumart_max_height - gwps->state->id3->albumart_height)/2;
+                break;
+            }
+        }
+
+        /* display cover */
+        gwps->display->set_drawmode(DRMODE_FG);
+        gwps->display->transparent_bitmap(
+                                (fb_data *)gwps->state->id3->albumart_data,
+                                x, y, gwps->state->id3->albumart_width,
+                                      gwps->state->id3->albumart_height);
+    }
+
     display->set_drawmode(DRMODE_SOLID);
 }
 #endif
@@ -2501,11 +2659,54 @@
     {
         gwps->display->stop_scroll();
         gwps->state->id3 = audio_current_track();
+
+        /* display album cover bitmap (if present and needed) */
+        if (gui_wps->data->wps_has_albumart
+            && gwps->state->id3->albumart_found)
+        {
+            if ((strcasecmp(cur_displayed_albumart_path,
+                           gwps->state->id3->albumart_path) != 0) ||
+                (cur_displayed_albumart_width != gui_wps->data->albumart_max_width) ||
+                (cur_displayed_albumart_height != gui_wps->data->albumart_max_height))
+            {
+                /* load the cover art bitmap */
+                int rc;
+                struct bitmap temp_bm;
+                temp_bm.data = gui_wps->data->img_buf_ptr;
+                rc = read_bmp_file(gwps->state->id3->albumart_path,
+                                   &temp_bm, gui_wps->data->img_buf_free,
+                                   FORMAT_NATIVE|FORMAT_TRANSPARENT,
+                                   gui_wps->data->albumart_max_width, gui_wps->data->albumart_max_height);
+                if (rc > 0)
+                {
+                    //gwps->state->id3->albumart_size = cur_displayed_albumart_size = rc;
+                    gwps->state->id3->albumart_width = cur_displayed_albumart_width = temp_bm.width;
+                    gwps->state->id3->albumart_height = cur_displayed_albumart_height = temp_bm.height;
+                    gwps->state->id3->albumart_data = (fb_data*)gui_wps->data->img_buf_ptr;
+                    strcpy(cur_displayed_albumart_path, gwps->state->id3->albumart_path);
+                    DEBUGF("** Loaded album art for %s : %d bytes\n", gwps->state->id3->path, rc);
+                }
+                else
+                {
+                    gwps->state->id3->albumart_data = NULL;
+                    strcpy(cur_displayed_albumart_path, "");
+                    DEBUGF("Loading album art for %s failed\n", gwps->state->id3->path);
+                }
+            }
+            else
+            {
+                gwps->state->id3->albumart_data = (fb_data*)gui_wps->data->img_buf_ptr;
+                gwps->state->id3->albumart_width = cur_displayed_albumart_width;
+                gwps->state->id3->albumart_height = cur_displayed_albumart_height;
+                //gwps->state->id3->albumart_size = cur_displayed_albumart_size;
+                DEBUGF("Skipped loading album art\n");
+            }
+        }
+
         if (gui_wps_display())
             retcode = true;
-        else{
+        else
             gui_wps_refresh(gwps, 0, WPS_REFRESH_ALL);
-        }
 
         if (gwps->state->id3)
             memcpy(gwps->state->current_track_path, gwps->state->id3->path,
Index: apps/gui/gwps.c
===================================================================
RCS file: /cvsroot/rockbox/apps/gui/gwps.c,v
retrieving revision 1.38
diff -u -r1.38 gwps.c
--- rockbox/apps/gui/gwps.c	11 Apr 2006 01:41:40 -0000	1.38
+++ apps/gui/gwps.c	12 Apr 2006 12:56:25 -0000
@@ -879,6 +879,7 @@
 static void wps_reset(struct wps_data *data)
 {
     data->wps_loaded = false;
+    data->wps_has_albumart = false;
     memset(&data->format_buffer, 0, sizeof data->format_buffer);
     wps_data_init(data);
 }
@@ -1063,3 +1064,20 @@
     unload_wps_backdrop();
 #endif
 }
+
+/*
+** returns true if at least one of the gui_wps screens
+**   have albumart in their wps structure
+*/
+bool gui_sync_wps_has_albumart(void)
+{
+    int  i;
+    FOR_NB_SCREENS(i) {
+        struct gui_wps *gwps = &gui_wps[i];
+        if (gwps->data && gwps->data->wps_has_albumart)
+            return true;
+    }
+    return false;
+}
+
+/* vi: set ts=4 sts=4 sw=4 et ai: */
Index: apps/gui/gwps.h
===================================================================
RCS file: /cvsroot/rockbox/apps/gui/gwps.h,v
retrieving revision 1.32
diff -u -r1.32 gwps.h
--- rockbox/apps/gui/gwps.h	10 Apr 2006 03:51:17 -0000	1.32
+++ apps/gui/gwps.h	12 Apr 2006 12:56:26 -0000
@@ -350,6 +350,15 @@
     int img_buf_free;
     bool wps_sb_tag;
     bool show_sb_on_wps;
+
+    /* album art support */
+    bool wps_has_albumart;
+    int albumart_x;
+    int albumart_y;
+    short albumart_xalign; /* WPS_ALIGN_CENTER, WPS_ALIGN_LEFT, WPS_ALIGN_RIGHT */
+    short albumart_yalign; /* WPS_ALIGN_CENTER, WPS_ALIGN_LEFT, WPS_ALIGN_RIGHT */
+    int albumart_max_width;
+    int albumart_max_height;
 #endif
 #ifdef HAVE_LCD_CHARCELLS
     unsigned char wps_progress_pat[8];
@@ -441,4 +450,8 @@
 void gui_sync_wps_init(void);
 void gui_sync_wps_screen_init(void);
 
+/* gives back if albumart should be loaded or not */
+bool gui_sync_wps_has_albumart(void);
+
+
 #endif
Index: firmware/export/id3.h
===================================================================
RCS file: /cvsroot/rockbox/firmware/export/id3.h,v
retrieving revision 1.26
diff -u -r1.26 id3.h
--- rockbox/firmware/export/id3.h	1 Feb 2006 16:42:02 -0000	1.26
+++ rockbox/firmware/export/id3.h	12 Apr 2006 12:56:26 -0000
@@ -22,6 +22,8 @@
 #include <stdbool.h>
 #include "config.h"
 #include "file.h"
+#include "lcd.h"
+#include "system.h"
 
 /* Audio file types. */
 /* NOTE: When adding new audio types, also add to codec_labels[] in id3.c */
@@ -125,6 +127,15 @@
     long track_peak;    /* 7.24 signed fixed point. 0 for no peak. */
     long album_peak;
 #endif
+
+#ifdef HAVE_LCD_BITMAP
+    /* album art support */
+    fb_data* albumart_data;
+    unsigned int albumart_width;
+    unsigned int albumart_height;
+    bool albumart_found;
+    char albumart_path[MAX_PATH];
+#endif
 };
 
 enum {
