FS#10365 - Optional debug output for albumart.c
[kugel-rb/myfork.git] / apps / recorder / albumart.c
blobe3cb5f10981f5782eee326eb60dff7aa52736bc2
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2007 Nicolas Pennequin
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include <string.h>
23 #include "sprintf.h"
24 #include "system.h"
25 #include "albumart.h"
26 #include "metadata.h"
27 #include "gwps.h"
28 #include "buffering.h"
29 #include "dircache.h"
30 #include "misc.h"
31 #include "settings.h"
33 /* Define LOGF_ENABLE to enable logf output in this file */
34 /*#define LOGF_ENABLE*/
35 #include "logf.h"
37 #ifdef SIMULATOR
38 #define LOGFQUEUE logf
39 #else
40 #define LOGFQUEUE(...)
41 #endif
43 #if defined(HAVE_JPEG) || defined(PLUGIN)
44 #define USE_JPEG_COVER
45 #endif
47 /* Strip filename from a full path
49 * buf - buffer to extract directory to.
50 * buf_size - size of buffer.
51 * fullpath - fullpath to extract from.
53 * Split the directory part of the given fullpath and store it in buf
54 * (including last '/').
55 * The function return parameter is a pointer to the filename
56 * inside the given fullpath.
58 static char* strip_filename(char* buf, int buf_size, const char* fullpath)
60 char* sep;
61 int len;
63 if (!buf || buf_size <= 0 || !fullpath)
64 return NULL;
66 /* if 'fullpath' is only a filename return immediately */
67 sep = strrchr(fullpath, '/');
68 if (sep == NULL)
70 buf[0] = 0;
71 return (char*)fullpath;
74 len = MIN(sep - fullpath + 1, buf_size - 1);
75 strncpy(buf, fullpath, len);
76 buf[len] = 0;
77 return (sep + 1);
80 /* Make sure part of path only contain chars valid for a FAT32 long name.
81 * Double quotes are replaced with single quotes, other unsupported chars
82 * are replaced with an underscore.
84 * path - path to modify.
85 * offset - where in path to start checking.
86 * count - number of chars to check.
88 static void fix_path_part(char* path, int offset, int count)
90 static const char invalid_chars[] = "*/:<>?\\|";
91 int i;
93 path += offset;
95 for (i = 0; i <= count; i++, path++)
97 if (*path == 0)
98 return;
99 if (*path == '"')
100 *path = '\'';
101 else if (strchr(invalid_chars, *path))
102 *path = '_';
106 #ifdef USE_JPEG_COVER
107 static const char * extensions[] = { "jpeg", "jpg", "bmp" };
108 static int extension_lens[] = { 4, 3, 3 };
109 /* Try checking for several file extensions, return true if a file is found and
110 * leaving the path modified to include the matching extension.
112 static bool try_exts(char *path, int len)
114 int i;
115 for (i = 0; i < 3; i++)
117 if (extension_lens[i] + len > MAX_PATH)
118 continue;
119 strcpy(path + len, extensions[i]);
120 if (file_exists(path))
121 return true;
123 return false;
125 #define EXT
126 #else
127 #define EXT "bmp"
128 #define try_exts(path, len) file_exists(path)
129 #endif
131 /* Look for the first matching album art bitmap in the following list:
132 * ./<trackname><size>.{jpeg,jpg,bmp}
133 * ./<albumname><size>.{jpeg,jpg,bmp}
134 * ./cover<size>.bmp
135 * ../<albumname><size>.{jpeg,jpg,bmp}
136 * ../cover<size>.{jpeg,jpg,bmp}
137 * ROCKBOX_DIR/albumart/<artist>-<albumname><size>.{jpeg,jpg,bmp}
138 * <size> is the value of the size_string parameter, <trackname> and
139 * <albumname> are read from the ID3 metadata.
140 * If a matching bitmap is found, its filename is stored in buf.
141 * Return value is true if a bitmap was found, false otherwise.
143 * If the first symbol in size_string is a colon (e.g. ":100x100")
144 * then the colon is skipped ("100x100" will be used) and the track
145 * specific image (./<trackname><size>.bmp) is tried last instead of first.
147 bool search_albumart_files(const struct mp3entry *id3, const char *size_string,
148 char *buf, int buflen)
150 char path[MAX_PATH + 1];
151 char dir[MAX_PATH + 1];
152 bool found = false;
153 int track_first = 1;
154 int pass;
155 const char *trackname;
156 const char *artist;
157 int dirlen;
158 int albumlen;
159 int pathlen;
161 if (!id3 || !buf)
162 return false;
164 trackname = id3->path;
166 if (strcmp(trackname, "No file!") == 0)
167 return false;
169 if (*size_string == ':')
171 size_string++;
172 track_first = 0;
175 strip_filename(dir, sizeof(dir), trackname);
176 dirlen = strlen(dir);
177 albumlen = id3->album ? strlen(id3->album) : 0;
179 for(pass = 0; pass < 2 - track_first; pass++)
181 if (track_first || pass)
183 /* the first file we look for is one specific to the
184 current track */
185 strip_extension(path, sizeof(path) - strlen(size_string) - 4,
186 trackname);
187 strcat(path, size_string);
188 strcat(path, "." EXT);
189 #ifdef USE_JPEG_COVER
190 pathlen = strlen(path);
191 #endif
192 found = try_exts(path, pathlen);
194 if (pass)
195 break;
196 if (!found && albumlen > 0)
198 /* if it doesn't exist,
199 * we look for a file specific to the track's album name */
200 pathlen = snprintf(path, sizeof(path),
201 "%s%s%s." EXT, dir, id3->album, size_string);
202 fix_path_part(path, dirlen, albumlen);
203 found = try_exts(path, pathlen);
206 if (!found)
208 /* if it still doesn't exist, we look for a generic file */
209 pathlen = snprintf(path, sizeof(path),
210 "%scover%s." EXT, dir, size_string);
211 found = try_exts(path, pathlen);
214 #ifdef USE_JPEG_COVER
215 if (!found && !*size_string)
217 snprintf (path, sizeof(path), "%sfolder.jpg", dir);
218 found = file_exists(path);
220 #endif
222 artist = id3->albumartist != NULL ? id3->albumartist : id3->artist;
224 if (!found && artist && id3->album)
226 /* look in the albumart subdir of .rockbox */
227 pathlen = snprintf(path, sizeof(path),
228 ROCKBOX_DIR "/albumart/%s-%s%s." EXT,
229 artist,
230 id3->album,
231 size_string);
232 fix_path_part(path, strlen(ROCKBOX_DIR "/albumart/"), MAX_PATH);
233 found = try_exts(path, pathlen);
236 if (!found)
238 /* if it still doesn't exist,
239 * we continue to search in the parent directory */
240 strcpy(path, dir);
241 path[dirlen - 1] = 0;
242 strip_filename(dir, sizeof(dir), path);
243 dirlen = strlen(dir);
246 /* only try parent if there is one */
247 if (dirlen > 0)
249 if (!found && albumlen > 0)
251 /* we look in the parent directory
252 * for a file specific to the track's album name */
253 pathlen = snprintf(path, sizeof(path),
254 "%s%s%s." EXT, dir, id3->album, size_string);
255 fix_path_part(path, dirlen, albumlen);
256 found = try_exts(path, pathlen);
259 if (!found)
261 /* if it still doesn't exist, we look in the parent directory
262 * for a generic file */
263 pathlen = snprintf(path, sizeof(path),
264 "%scover%s." EXT, dir, size_string);
265 found = try_exts(path, pathlen);
268 if (found)
269 break;
272 if (!found)
273 return false;
275 strncpy(buf, path, buflen);
276 LOGFQUEUE("Album art found: %s", path);
277 return true;
280 #ifndef PLUGIN
281 /* Look for albumart bitmap in the same dir as the track and in its parent dir.
282 * Stores the found filename in the buf parameter.
283 * Returns true if a bitmap was found, false otherwise */
284 bool find_albumart(const struct mp3entry *id3, char *buf, int buflen)
286 if (!id3 || !buf)
287 return false;
289 char size_string[9];
290 struct wps_data *data = gui_wps[0].data;
292 if (!data)
293 return false;
295 LOGFQUEUE("Looking for album art for %s", id3->path);
297 /* Write the size string, e.g. ".100x100". */
298 snprintf(size_string, sizeof(size_string), ".%dx%d",
299 data->albumart_max_width, data->albumart_max_height);
301 /* First we look for a bitmap of the right size */
302 if (search_albumart_files(id3, size_string, buf, buflen))
303 return true;
305 /* Then we look for generic bitmaps */
306 *size_string = 0;
307 return search_albumart_files(id3, size_string, buf, buflen);
310 /* Draw the album art bitmap from the given handle ID onto the given WPS.
311 Call with clear = true to clear the bitmap instead of drawing it. */
312 void draw_album_art(struct gui_wps *gwps, int handle_id, bool clear)
314 if (!gwps || !gwps->data || !gwps->display || handle_id < 0)
315 return;
317 struct wps_data *data = gwps->data;
319 #ifdef HAVE_REMOTE_LCD
320 /* No album art on RWPS */
321 if (data->remote_wps)
322 return;
323 #endif
325 struct bitmap *bmp;
326 if (bufgetdata(handle_id, 0, (void *)&bmp) <= 0)
327 return;
329 short x = data->albumart_x;
330 short y = data->albumart_y;
331 short width = bmp->width;
332 short height = bmp->height;
334 if (data->albumart_max_width > 0)
336 /* Crop if the bitmap is too wide */
337 width = MIN(bmp->width, data->albumart_max_width);
339 /* Align */
340 if (data->albumart_xalign & WPS_ALBUMART_ALIGN_RIGHT)
341 x += data->albumart_max_width - width;
342 else if (data->albumart_xalign & WPS_ALBUMART_ALIGN_CENTER)
343 x += (data->albumart_max_width - width) / 2;
346 if (data->albumart_max_height > 0)
348 /* Crop if the bitmap is too high */
349 height = MIN(bmp->height, data->albumart_max_height);
351 /* Align */
352 if (data->albumart_yalign & WPS_ALBUMART_ALIGN_BOTTOM)
353 y += data->albumart_max_height - height;
354 else if (data->albumart_yalign & WPS_ALBUMART_ALIGN_CENTER)
355 y += (data->albumart_max_height - height) / 2;
358 if (!clear)
360 /* Draw the bitmap */
361 gwps->display->bitmap_part((fb_data*)bmp->data, 0, 0, bmp->width,
362 x, y, width, height);
363 #ifdef HAVE_LCD_INVERT
364 if (global_settings.invert) {
365 gwps->display->set_drawmode(DRMODE_COMPLEMENT);
366 gwps->display->fillrect(x, y, width, height);
367 gwps->display->set_drawmode(DRMODE_SOLID);
369 #endif
371 else
373 /* Clear the bitmap */
374 gwps->display->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
375 gwps->display->fillrect(x, y, width, height);
376 gwps->display->set_drawmode(DRMODE_SOLID);
380 void get_albumart_size(struct bitmap *bmp)
382 /* FIXME: What should we do with albumart on remote? */
383 struct wps_data *data = gui_wps[0].data;
385 bmp->width = data->albumart_max_width;
386 bmp->height = data->albumart_max_height;
388 #endif /* PLUGIN */