Bump version numbers for 3.13
[maemo-rb.git] / apps / recorder / albumart.c
blob4cbabbc8ce70e9490b638058ff5694fe7dc8b3a6
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 <stdio.h>
23 #include "string-extra.h"
24 #include "system.h"
25 #include "albumart.h"
26 #include "metadata.h"
27 #include "buffering.h"
28 #include "dircache.h"
29 #include "misc.h"
30 #include "filefuncs.h"
31 #include "settings.h"
32 #include "wps.h"
34 /* Define LOGF_ENABLE to enable logf output in this file */
35 /*#define LOGF_ENABLE*/
36 #include "logf.h"
38 #if defined(HAVE_JPEG) || defined(PLUGIN)
39 #define USE_JPEG_COVER
40 #endif
42 /* Strip filename from a full path
44 * buf - buffer to extract directory to.
45 * buf_size - size of buffer.
46 * fullpath - fullpath to extract from.
48 * Split the directory part of the given fullpath and store it in buf
49 * (including last '/').
50 * The function return parameter is a pointer to the filename
51 * inside the given fullpath.
53 static char* strip_filename(char* buf, int buf_size, const char* fullpath)
55 char* sep;
56 int len;
58 if (!buf || buf_size <= 0 || !fullpath)
59 return NULL;
61 /* if 'fullpath' is only a filename return immediately */
62 sep = strrchr(fullpath, '/');
63 if (sep == NULL)
65 buf[0] = 0;
66 return (char*)fullpath;
69 len = MIN(sep - fullpath + 1, buf_size - 1);
70 strlcpy(buf, fullpath, len + 1);
71 return (sep + 1);
74 /* Make sure part of path only contain chars valid for a FAT32 long name.
75 * Double quotes are replaced with single quotes, other unsupported chars
76 * are replaced with an underscore.
78 * path - path to modify.
79 * offset - where in path to start checking.
80 * count - number of chars to check.
82 static void fix_path_part(char* path, int offset, int count)
84 static const char invalid_chars[] = "*/:<>?\\|";
85 int i;
87 path += offset;
89 for (i = 0; i <= count; i++, path++)
91 if (*path == 0)
92 return;
93 if (*path == '"')
94 *path = '\'';
95 else if (strchr(invalid_chars, *path))
96 *path = '_';
100 #ifdef USE_JPEG_COVER
101 static const char * extensions[] = { "jpeg", "jpg", "bmp" };
102 static const unsigned char extension_lens[] = { 4, 3, 3 };
103 /* Try checking for several file extensions, return true if a file is found and
104 * leaving the path modified to include the matching extension.
106 static bool try_exts(char *path, int len)
108 int i;
109 for (i = 0; i < 3; i++)
111 if (extension_lens[i] + len > MAX_PATH)
112 continue;
113 strcpy(path + len, extensions[i]);
114 if (file_exists(path))
115 return true;
117 return false;
119 #define EXT
120 #else
121 #define EXT "bmp"
122 #define try_exts(path, len) file_exists(path)
123 #endif
125 /* Look for the first matching album art bitmap in the following list:
126 * ./<trackname><size>.{jpeg,jpg,bmp}
127 * ./<albumname><size>.{jpeg,jpg,bmp}
128 * ./cover<size>.bmp
129 * ../<albumname><size>.{jpeg,jpg,bmp}
130 * ../cover<size>.{jpeg,jpg,bmp}
131 * ROCKBOX_DIR/albumart/<artist>-<albumname><size>.{jpeg,jpg,bmp}
132 * <size> is the value of the size_string parameter, <trackname> and
133 * <albumname> are read from the ID3 metadata.
134 * If a matching bitmap is found, its filename is stored in buf.
135 * Return value is true if a bitmap was found, false otherwise.
137 * If the first symbol in size_string is a colon (e.g. ":100x100")
138 * then the colon is skipped ("100x100" will be used) and the track
139 * specific image (./<trackname><size>.bmp) is tried last instead of first.
141 bool search_albumart_files(const struct mp3entry *id3, const char *size_string,
142 char *buf, int buflen)
144 char path[MAX_PATH + 1];
145 char dir[MAX_PATH + 1];
146 bool found = false;
147 int track_first = 1;
148 int pass;
149 const char *trackname;
150 const char *artist;
151 int dirlen;
152 int albumlen;
153 int pathlen;
155 if (!id3 || !buf)
156 return false;
158 trackname = id3->path;
160 if (strcmp(trackname, "No file!") == 0)
161 return false;
163 if (*size_string == ':')
165 size_string++;
166 track_first = 0;
169 strip_filename(dir, sizeof(dir), trackname);
170 dirlen = strlen(dir);
171 albumlen = id3->album ? strlen(id3->album) : 0;
173 for(pass = 0; pass < 2 - track_first; pass++)
175 if (track_first || pass)
177 /* the first file we look for is one specific to the
178 current track */
179 strip_extension(path, sizeof(path) - strlen(size_string) - 4,
180 trackname);
181 strcat(path, size_string);
182 strcat(path, "." EXT);
183 #ifdef USE_JPEG_COVER
184 pathlen = strlen(path);
185 #endif
186 found = try_exts(path, pathlen);
188 if (pass)
189 break;
190 if (!found && albumlen > 0)
192 /* if it doesn't exist,
193 * we look for a file specific to the track's album name */
194 pathlen = snprintf(path, sizeof(path),
195 "%s%s%s." EXT, dir, id3->album, size_string);
196 fix_path_part(path, dirlen, albumlen);
197 found = try_exts(path, pathlen);
200 if (!found)
202 /* if it still doesn't exist, we look for a generic file */
203 pathlen = snprintf(path, sizeof(path),
204 "%scover%s." EXT, dir, size_string);
205 found = try_exts(path, pathlen);
208 #ifdef USE_JPEG_COVER
209 if (!found && !*size_string)
211 snprintf (path, sizeof(path), "%sfolder.jpg", dir);
212 found = file_exists(path);
214 #endif
216 artist = id3->albumartist != NULL ? id3->albumartist : id3->artist;
218 if (!found && artist && id3->album)
220 /* look in the albumart subdir of .rockbox */
221 pathlen = snprintf(path, sizeof(path),
222 ROCKBOX_DIR "/albumart/%s-%s%s." EXT,
223 artist,
224 id3->album,
225 size_string);
226 fix_path_part(path, strlen(ROCKBOX_DIR "/albumart/"), MAX_PATH);
227 found = try_exts(path, pathlen);
230 if (!found)
232 /* if it still doesn't exist,
233 * we continue to search in the parent directory */
234 strcpy(path, dir);
235 path[dirlen - 1] = 0;
236 strip_filename(dir, sizeof(dir), path);
237 dirlen = strlen(dir);
240 /* only try parent if there is one */
241 if (dirlen > 0)
243 if (!found && albumlen > 0)
245 /* we look in the parent directory
246 * for a file specific to the track's album name */
247 pathlen = snprintf(path, sizeof(path),
248 "%s%s%s." EXT, dir, id3->album, size_string);
249 fix_path_part(path, dirlen, albumlen);
250 found = try_exts(path, pathlen);
253 if (!found)
255 /* if it still doesn't exist, we look in the parent directory
256 * for a generic file */
257 pathlen = snprintf(path, sizeof(path),
258 "%scover%s." EXT, dir, size_string);
259 found = try_exts(path, pathlen);
262 if (found)
263 break;
266 if (!found)
267 return false;
269 strlcpy(buf, path, buflen);
270 logf("Album art found: %s", path);
271 return true;
274 #ifndef PLUGIN
275 /* Look for albumart bitmap in the same dir as the track and in its parent dir.
276 * Stores the found filename in the buf parameter.
277 * Returns true if a bitmap was found, false otherwise */
278 bool find_albumart(const struct mp3entry *id3, char *buf, int buflen,
279 const struct dim *dim)
281 if (!id3 || !buf)
282 return false;
284 char size_string[9];
285 logf("Looking for album art for %s", id3->path);
287 /* Write the size string, e.g. ".100x100". */
288 snprintf(size_string, sizeof(size_string), ".%dx%d",
289 dim->width, dim->height);
291 /* First we look for a bitmap of the right size */
292 if (search_albumart_files(id3, size_string, buf, buflen))
293 return true;
295 /* Then we look for generic bitmaps */
296 *size_string = 0;
297 return search_albumart_files(id3, size_string, buf, buflen);
300 /* Draw the album art bitmap from the given handle ID onto the given WPS.
301 Call with clear = true to clear the bitmap instead of drawing it. */
302 void draw_album_art(struct gui_wps *gwps, int handle_id, bool clear)
304 if (!gwps || !gwps->data || !gwps->display || handle_id < 0)
305 return;
307 struct wps_data *data = gwps->data;
308 struct skin_albumart *aa = SKINOFFSETTOPTR(get_skin_buffer(data), data->albumart);
310 if (!aa)
311 return;
313 struct bitmap *bmp;
314 if (bufgetdata(handle_id, 0, (void *)&bmp) <= 0)
315 return;
317 short x = aa->x;
318 short y = aa->y;
319 short width = bmp->width;
320 short height = bmp->height;
322 if (aa->width > 0)
324 /* Crop if the bitmap is too wide */
325 width = MIN(bmp->width, aa->width);
327 /* Align */
328 if (aa->xalign & WPS_ALBUMART_ALIGN_RIGHT)
329 x += aa->width - width;
330 else if (aa->xalign & WPS_ALBUMART_ALIGN_CENTER)
331 x += (aa->width - width) / 2;
334 if (aa->height > 0)
336 /* Crop if the bitmap is too high */
337 height = MIN(bmp->height, aa->height);
339 /* Align */
340 if (aa->yalign & WPS_ALBUMART_ALIGN_BOTTOM)
341 y += aa->height - height;
342 else if (aa->yalign & WPS_ALBUMART_ALIGN_CENTER)
343 y += (aa->height - height) / 2;
346 if (!clear)
348 /* Draw the bitmap */
349 gwps->display->bitmap_part((fb_data*)bmp->data, 0, 0,
350 STRIDE(gwps->display->screen_type,
351 bmp->width, bmp->height),
352 x, y, width, height);
353 #ifdef HAVE_LCD_INVERT
354 if (global_settings.invert) {
355 gwps->display->set_drawmode(DRMODE_COMPLEMENT);
356 gwps->display->fillrect(x, y, width, height);
357 gwps->display->set_drawmode(DRMODE_SOLID);
359 #endif
361 else
363 /* Clear the bitmap */
364 gwps->display->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
365 gwps->display->fillrect(x, y, width, height);
366 gwps->display->set_drawmode(DRMODE_SOLID);
370 #endif /* PLUGIN */