Build pictureflow using overlay on lowmem targets, support JPEG AA in PF on all targets.
[kugel-rb.git] / apps / recorder / albumart.c
blob24b01f9c529a9d14412b0c689478b1ce378eb492
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 "debug.h"
31 #include "misc.h"
32 #include "settings.h"
35 /* Strip filename from a full path
37 * buf - buffer to extract directory to.
38 * buf_size - size of buffer.
39 * fullpath - fullpath to extract from.
41 * Split the directory part of the given fullpath and store it in buf
42 * (including last '/').
43 * The function return parameter is a pointer to the filename
44 * inside the given fullpath.
46 static char* strip_filename(char* buf, int buf_size, const char* fullpath)
48 char* sep;
49 int len;
51 if (!buf || buf_size <= 0 || !fullpath)
52 return NULL;
54 /* if 'fullpath' is only a filename return immediately */
55 sep = strrchr(fullpath, '/');
56 if (sep == NULL)
58 buf[0] = 0;
59 return (char*)fullpath;
62 len = MIN(sep - fullpath + 1, buf_size - 1);
63 strncpy(buf, fullpath, len);
64 buf[len] = 0;
65 return (sep + 1);
68 /* Make sure part of path only contain chars valid for a FAT32 long name.
69 * Double quotes are replaced with single quotes, other unsupported chars
70 * are replaced with an underscore.
72 * path - path to modify.
73 * offset - where in path to start checking.
74 * count - number of chars to check.
76 static void fix_path_part(char* path, int offset, int count)
78 static const char invalid_chars[] = "*/:<>?\\|";
79 int i;
81 path += offset;
83 for (i = 0; i <= count; i++, path++)
85 if (*path == 0)
86 return;
87 if (*path == '"')
88 *path = '\'';
89 else if (strchr(invalid_chars, *path))
90 *path = '_';
94 #if defined(HAVE_JPEG) || defined(PLUGIN)
95 const char * extensions[] = { "jpeg", "jpg", "bmp" };
96 int extension_lens[] = { 4, 3, 3 };
97 /* Try checking for several file extensions, return true if a file is found and
98 * leaving the path modified to include the matching extension.
100 static bool try_exts(char *path, int len)
102 int i;
103 for (i = 0; i < 3; i++)
105 if (extension_lens[i] + len > MAX_PATH)
106 continue;
107 strcpy(path + len, extensions[i]);
108 if (file_exists(path))
109 return true;
111 return false;
113 #endif
115 /* Look for the first matching album art bitmap in the following list:
116 * ./<trackname><size>.bmp
117 * ./<albumname><size>.bmp
118 * ./cover<size>.bmp
119 * ../<albumname><size>.bmp
120 * ../cover<size>.bmp
121 * ROCKBOX_DIR/albumart/<artist>-<albumname><size>.bmp
122 * <size> is the value of the size_string parameter, <trackname> and
123 * <albumname> are read from the ID3 metadata.
124 * If a matching bitmap is found, its filename is stored in buf.
125 * Return value is true if a bitmap was found, false otherwise.
127 bool search_albumart_files(const struct mp3entry *id3, const char *size_string,
128 char *buf, int buflen)
130 char path[MAX_PATH + 1];
131 char dir[MAX_PATH + 1];
132 bool found = false;
133 const char *trackname;
134 const char *artist;
135 int dirlen;
136 int albumlen;
137 #if defined(HAVE_JPEG) || defined(PLUGIN)
138 int pathlen;
139 #endif
141 if (!id3 || !buf)
142 return false;
144 trackname = id3->path;
146 if (strcmp(trackname, "No file!") == 0)
147 return false;
149 strip_filename(dir, sizeof(dir), trackname);
150 dirlen = strlen(dir);
151 albumlen = id3->album ? strlen(id3->album) : 0;
153 /* the first file we look for is one specific to the track playing */
154 strip_extension(path, sizeof(path) - strlen(size_string) - 4, trackname);
155 strcat(path, size_string);
156 #if defined(HAVE_JPEG) || defined(PLUGIN)
157 strcat(path, ".");
158 pathlen = strlen(path);
159 found = try_exts(path, pathlen);
160 #else
161 strcat(path, ".bmp");
162 found = file_exists(path);
163 #endif
164 if (!found && albumlen > 0)
166 /* if it doesn't exist,
167 * we look for a file specific to the track's album name */
168 #if defined(HAVE_JPEG) || defined(PLUGIN)
169 pathlen = snprintf(path, sizeof(path),
170 "%s%s%s.", dir, id3->album, size_string);
171 fix_path_part(path, dirlen, albumlen);
172 found = try_exts(path, pathlen);
173 #else
174 snprintf(path, sizeof(path),
175 "%s%s%s.bmp", dir, id3->album, size_string);
176 fix_path_part(path, dirlen, albumlen);
177 found = file_exists(path);
178 #endif
181 if (!found)
183 /* if it still doesn't exist, we look for a generic file */
184 #if defined(HAVE_JPEG) || defined(PLUGIN)
185 pathlen = snprintf(path, sizeof(path),
186 "%scover%s.", dir, size_string);
187 found = try_exts(path, pathlen);
188 #else
189 snprintf(path, sizeof(path),
190 "%scover%s.bmp", dir, size_string);
191 found = file_exists(path);
192 #endif
195 #if defined(HAVE_JPEG) || defined(PLUGIN)
196 if (!found)
198 snprintf (path, sizeof(path), "%sfolder.jpg", dir);
199 found = file_exists(path);
201 #endif
203 artist = id3->albumartist != NULL ? id3->albumartist : id3->artist;
205 if (!found && artist && id3->album)
207 /* look in the albumart subdir of .rockbox */
208 #if defined(HAVE_JPEG) || defined(PLUGIN)
209 pathlen = snprintf(path, sizeof(path),
210 ROCKBOX_DIR "/albumart/%s-%s%s.",
211 artist,
212 id3->album,
213 size_string);
214 fix_path_part(path, strlen(ROCKBOX_DIR "/albumart/"), MAX_PATH);
215 found = try_exts(path, pathlen);
216 #else
217 snprintf(path, sizeof(path),
218 ROCKBOX_DIR "/albumart/%s-%s%s.bmp",
219 artist,
220 id3->album,
221 size_string);
222 fix_path_part(path, strlen(ROCKBOX_DIR "/albumart/"), MAX_PATH);
223 found = file_exists(path);
224 #endif
227 if (!found)
229 /* if it still doesn't exist,
230 * we continue to search in the parent directory */
231 strcpy(path, dir);
232 path[dirlen - 1] = 0;
233 strip_filename(dir, sizeof(dir), path);
234 dirlen = strlen(dir);
237 /* only try parent if there is one */
238 if (dirlen > 0)
240 if (!found && albumlen > 0)
242 /* we look in the parent directory
243 * for a file specific to the track's album name */
244 #if defined(HAVE_JPEG) || defined(PLUGIN)
245 pathlen = snprintf(path, sizeof(path),
246 "%s%s%s.", dir, id3->album, size_string);
247 fix_path_part(path, dirlen, albumlen);
248 found = try_exts(path, pathlen);
249 #else
250 snprintf(path, sizeof(path),
251 "%s%s%s.bmp", dir, id3->album, size_string);
252 fix_path_part(path, dirlen, albumlen);
253 found = file_exists(path);
254 #endif
257 if (!found)
259 /* if it still doesn't exist, we look in the parent directory
260 * for a generic file */
261 #if defined(HAVE_JPEG) || defined(PLUGIN)
262 pathlen = snprintf(path, sizeof(path),
263 "%scover%s.", dir, size_string);
264 found = try_exts(path, pathlen);
265 #else
266 snprintf(path, sizeof(path),
267 "%scover%s.bmp", dir, size_string);
268 found = file_exists(path);
269 #endif
273 if (!found)
274 return false;
276 strncpy(buf, path, buflen);
277 DEBUGF("Album art found: %s\n", path);
278 return true;
281 #ifndef PLUGIN
282 /* Look for albumart bitmap in the same dir as the track and in its parent dir.
283 * Stores the found filename in the buf parameter.
284 * Returns true if a bitmap was found, false otherwise */
285 bool find_albumart(const struct mp3entry *id3, char *buf, int buflen)
287 if (!id3 || !buf)
288 return false;
290 char size_string[9];
291 struct wps_data *data = gui_wps[0].data;
293 if (!data)
294 return false;
296 DEBUGF("Looking for album art for %s\n", id3->path);
298 /* Write the size string, e.g. ".100x100". */
299 snprintf(size_string, sizeof(size_string), ".%dx%d",
300 data->albumart_max_width, data->albumart_max_height);
302 /* First we look for a bitmap of the right size */
303 if (search_albumart_files(id3, size_string, buf, buflen))
304 return true;
306 /* Then we look for generic bitmaps */
307 *size_string = 0;
308 return search_albumart_files(id3, size_string, buf, buflen);
311 /* Draw the album art bitmap from the given handle ID onto the given WPS.
312 Call with clear = true to clear the bitmap instead of drawing it. */
313 void draw_album_art(struct gui_wps *gwps, int handle_id, bool clear)
315 if (!gwps || !gwps->data || !gwps->display || handle_id < 0)
316 return;
318 struct wps_data *data = gwps->data;
320 #ifdef HAVE_REMOTE_LCD
321 /* No album art on RWPS */
322 if (data->remote_wps)
323 return;
324 #endif
326 struct bitmap *bmp;
327 if (bufgetdata(handle_id, 0, (void *)&bmp) <= 0)
328 return;
330 short x = data->albumart_x;
331 short y = data->albumart_y;
332 short width = bmp->width;
333 short height = bmp->height;
335 if (data->albumart_max_width > 0)
337 /* Crop if the bitmap is too wide */
338 width = MIN(bmp->width, data->albumart_max_width);
340 /* Align */
341 if (data->albumart_xalign & WPS_ALBUMART_ALIGN_RIGHT)
342 x += data->albumart_max_width - width;
343 else if (data->albumart_xalign & WPS_ALBUMART_ALIGN_CENTER)
344 x += (data->albumart_max_width - width) / 2;
347 if (data->albumart_max_height > 0)
349 /* Crop if the bitmap is too high */
350 height = MIN(bmp->height, data->albumart_max_height);
352 /* Align */
353 if (data->albumart_yalign & WPS_ALBUMART_ALIGN_BOTTOM)
354 y += data->albumart_max_height - height;
355 else if (data->albumart_yalign & WPS_ALBUMART_ALIGN_CENTER)
356 y += (data->albumart_max_height - height) / 2;
359 if (!clear)
361 /* Draw the bitmap */
362 gwps->display->bitmap_part((fb_data*)bmp->data, 0, 0, bmp->width,
363 x, y, width, height);
364 #ifdef HAVE_LCD_INVERT
365 if (global_settings.invert) {
366 gwps->display->set_drawmode(DRMODE_COMPLEMENT);
367 gwps->display->fillrect(x, y, width, height);
368 gwps->display->set_drawmode(DRMODE_SOLID);
370 #endif
372 else
374 /* Clear the bitmap */
375 gwps->display->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
376 gwps->display->fillrect(x, y, width, height);
377 gwps->display->set_drawmode(DRMODE_SOLID);
381 void get_albumart_size(struct bitmap *bmp)
383 /* FIXME: What should we do with albumart on remote? */
384 struct wps_data *data = gui_wps[0].data;
386 bmp->width = data->albumart_max_width;
387 bmp->height = data->albumart_max_height;
389 #endif /* PLUGIN */