summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristophe Fergeau <teuf@gnome.org>2005-11-23 18:21:52 +0000
committerChristophe Fergeau <teuf@gnome.org>2005-11-23 18:21:52 +0000
commit413674fba5e513b11b0522fb5cc9356169f7c85d (patch)
treec32d396b78585c2673f4c2c3a54093923c93c6fe
parent9158245f35d7a8007fa650d8e9c5549606a5151a (diff)
downloadlibgpod-tmz-413674fba5e513b11b0522fb5cc9356169f7c85d.tar.gz
libgpod-tmz-413674fba5e513b11b0522fb5cc9356169f7c85d.tar.xz
libgpod-tmz-413674fba5e513b11b0522fb5cc9356169f7c85d.zip
2005-11-23 Christophe Fergeau <teuf@gnome.org>
* src/db-artwork-debug.c: (get_utf16_string): * src/db-artwork-parser.c: (get_utf16_string), (parse_mhod_3), (parse_mhni), (ipod_supports_cover_art), (ipod_parse_artwork_db): * src/db-artwork-parser.h: * src/db-artwork-writer.c: (get_artwork_info), (write_mhod_type_3), (write_mhni), (write_mhod), (write_mhii), (write_mhif): * src/db-image-parser.c: (unpack_RGB_565), (image_type_from_corr_id), (ipod_image_new_from_mhni): * src/db-image-parser.h: * src/itdb.h: * src/ithumb-writer.c: (pack_RGB_565), (ithumb_writer_write_thumbnail), (ipod_image_get_ithmb_filename), (ithumb_writer_new), (ithumb_writer_free), (write_thumbnail), (itdb_write_ithumb_files): * tests/test-covers.c: (save_song_thumbnails): rework artwork code in an attempt to properly support artwork on all the iPod models git-svn-id: https://gtkpod.svn.sf.net/svnroot/gtkpod/libgpod/trunk@1171 f01d2545-417e-4e96-918e-98f8d0dbbcb6
-rw-r--r--ChangeLog19
-rw-r--r--src/db-artwork-debug.c3
-rw-r--r--src/db-artwork-parser.c87
-rw-r--r--src/db-artwork-parser.h6
-rw-r--r--src/db-artwork-writer.c106
-rw-r--r--src/db-image-parser.c56
-rw-r--r--src/db-image-parser.h4
-rw-r--r--src/itdb.h6
-rw-r--r--src/ithumb-writer.c177
-rw-r--r--tests/test-covers.c11
10 files changed, 270 insertions, 205 deletions
diff --git a/ChangeLog b/ChangeLog
index 26e4f3a..83cfd62 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,24 @@
2005-11-23 Christophe Fergeau <teuf@gnome.org>
+ * src/db-artwork-debug.c: (get_utf16_string):
+ * src/db-artwork-parser.c: (get_utf16_string), (parse_mhod_3),
+ (parse_mhni), (ipod_supports_cover_art), (ipod_parse_artwork_db):
+ * src/db-artwork-parser.h:
+ * src/db-artwork-writer.c: (get_artwork_info), (write_mhod_type_3),
+ (write_mhni), (write_mhod), (write_mhii), (write_mhif):
+ * src/db-image-parser.c: (unpack_RGB_565),
+ (image_type_from_corr_id), (ipod_image_new_from_mhni):
+ * src/db-image-parser.h:
+ * src/itdb.h:
+ * src/ithumb-writer.c: (pack_RGB_565),
+ (ithumb_writer_write_thumbnail), (ipod_image_get_ithmb_filename),
+ (ithumb_writer_new), (ithumb_writer_free), (write_thumbnail),
+ (itdb_write_ithumb_files):
+ * tests/test-covers.c: (save_song_thumbnails): rework artwork code in
+ an attempt to properly support artwork on all the iPod models
+
+2005-11-23 Christophe Fergeau <teuf@gnome.org>
+
* src/hal-common.c:
* tests/test-covers.c: (ipod_image_to_gdk_pixbuf): more glib 2.4
changes
diff --git a/src/db-artwork-debug.c b/src/db-artwork-debug.c
index 90e4107..3903038 100644
--- a/src/db-artwork-debug.c
+++ b/src/db-artwork-debug.c
@@ -65,8 +65,7 @@ get_utf16_string (void* buffer, gint length)
result = g_utf16_to_utf8 (tmp, length/2, NULL, NULL, NULL);
g_free (tmp);
- return result;
-
+ return result;
}
G_GNUC_INTERNAL void
diff --git a/src/db-artwork-parser.c b/src/db-artwork-parser.c
index 4ec007e..4a1997c 100644
--- a/src/db-artwork-parser.c
+++ b/src/db-artwork-parser.c
@@ -78,9 +78,28 @@ parse_mhia (DBParseContext *ctx, Itdb_iTunesDB *db, GError *error)
return 0;
}
-#ifdef DEBUG_ARTWORKDB
+static char *
+get_utf16_string (void* buffer, gint length)
+{
+ char *result;
+ gunichar2 *tmp;
+ int i;
+ /* Byte-swap the utf16 characters if necessary (I'm relying
+ * on gcc to optimize most of this code away on LE platforms)
+ */
+ tmp = g_memdup (buffer, length);
+ for (i = 0; i < length/2; i++) {
+ tmp[i] = GINT16_FROM_LE (tmp[i]);
+ }
+ result = g_utf16_to_utf8 (tmp, length/2, NULL, NULL, NULL);
+ g_free (tmp);
+
+ return result;
+
+}
+
static int
-parse_mhod_3 (DBParseContext *ctx, GError *error)
+parse_mhod_3 (DBParseContext *ctx, Itdb_Image *image, GError *error)
{
MhodHeader *mhod;
MhodHeaderArtworkType3 *mhod3;
@@ -98,50 +117,37 @@ parse_mhod_3 (DBParseContext *ctx, GError *error)
if ((GINT_FROM_LE (mhod3->type) & 0x00FFFFFF) != MHOD_ARTWORK_TYPE_FILE_NAME) {
return -1;
}
-
+ image->filename = get_utf16_string (mhod3->string, mhod3->string_len);
dump_mhod_type_3 (mhod3);
return 0;
}
-#endif
static int
parse_mhni (DBParseContext *ctx, iPodSong *song, GError *error)
{
MhniHeader *mhni;
-#ifndef DEBUG_ARTWORKDB
+ DBParseContext *mhod_ctx;
Itdb_Image *thumb;
-#endif
mhni = db_parse_context_get_m_header (ctx, MhniHeader, "mhni");
if (mhni == NULL) {
return -1;
}
db_parse_context_set_total_len (ctx, GINT_FROM_LE (mhni->total_len));
-
dump_mhni (mhni);
-#ifdef DEBUG_ARTWORKDB
- {
- DBParseContext *mhod_ctx;
-
- /* No information useful to us in mhod type 3, do not parse
- * it in non-debug mode
- * FIXME: really? it contains the thumbnail file name!
- * we infer it from the correlation id, but is this
- * always The Right Thing to do?
- */
- mhod_ctx = db_parse_context_get_sub_context (ctx, ctx->header_len);
- if (mhod_ctx == NULL) {
- return -1;
- }
- parse_mhod_3 (mhod_ctx, NULL);
- g_free (mhod_ctx);
- }
-#else
- thumb = ipod_image_new_from_mhni (mhni, song->itdb->mountpoint);
+
+ thumb = ipod_image_new_from_mhni (mhni, song->itdb);
if (thumb != NULL) {
song->thumbnails = g_list_append (song->thumbnails, thumb);
}
-#endif
+
+ mhod_ctx = db_parse_context_get_sub_context (ctx, ctx->header_len);
+ if (mhod_ctx == NULL) {
+ return -1;
+ }
+ parse_mhod_3 (mhod_ctx, thumb, error);
+ g_free (mhod_ctx);
+
return 0;
}
@@ -422,6 +428,30 @@ ipod_db_get_photo_db_path (const char *mount_point)
}
+static gboolean
+ipod_supports_cover_art (IpodDevice *ipod)
+{
+ const IpodArtworkFormat *formats;
+
+ if (ipod == NULL) {
+ return FALSE;
+ }
+
+ g_object_get (G_OBJECT (ipod), "artwork-formats", &formats, NULL);
+ if (formats == NULL) {
+ return FALSE;
+ }
+
+ while (formats->type != -1) {
+ if ((formats->type == IPOD_COVER_SMALL)
+ || (formats->type == IPOD_COVER_LARGE)) {
+ return TRUE;
+ }
+ formats++;
+ }
+
+ return FALSE;
+}
int
ipod_parse_artwork_db (Itdb_iTunesDB *db)
@@ -431,6 +461,9 @@ ipod_parse_artwork_db (Itdb_iTunesDB *db)
g_return_val_if_fail (db, -1);
+ if (!ipod_supports_cover_art (db->device)) {
+ return -1;
+ }
ctx = NULL;
filename = ipod_db_get_artwork_db_path (db->mountpoint);
if (filename == NULL) {
diff --git a/src/db-artwork-parser.h b/src/db-artwork-parser.h
index da8e743..5c117fa 100644
--- a/src/db-artwork-parser.h
+++ b/src/db-artwork-parser.h
@@ -30,12 +30,6 @@
#define iPodSong Itdb_Track
-#define IPOD_THUMBNAIL_FULL_SIZE_CORRELATION_ID 1016
-#define IPOD_THUMBNAIL_NOW_PLAYING_CORRELATION_ID 1017
-#define IPOD_NANO_THUMBNAIL_FULL_SIZE_CORRELATION_ID 1027
-#define IPOD_NANO_THUMBNAIL_NOW_PLAYING_CORRELATION_ID 1031
-
-
G_GNUC_INTERNAL int ipod_parse_photo_db (const char *filename);
G_GNUC_INTERNAL int ipod_parse_artwork_db (Itdb_iTunesDB *db);
G_GNUC_INTERNAL int ipod_write_artwork_db (Itdb_iTunesDB *db);
diff --git a/src/db-artwork-writer.c b/src/db-artwork-writer.c
index a65df2b..33e673c 100644
--- a/src/db-artwork-writer.c
+++ b/src/db-artwork-writer.c
@@ -240,6 +240,33 @@ enum iPodThumbnailType {
#define RETURN_SIZE_FOR(id, size) if (strncmp (id, header_id, 4) == 0) return (size)
+
+static const IpodArtworkFormat *
+get_artwork_info (IpodDevice *ipod, int image_type)
+{
+ const IpodArtworkFormat *formats;
+
+ if (ipod == NULL) {
+ return NULL;
+ }
+
+ g_object_get (G_OBJECT (ipod), "artwork-formats", &formats, NULL);
+ if (formats == NULL) {
+ return NULL;
+ }
+
+ while ((formats->type != -1) && (formats->type != image_type)) {
+ formats++;
+ }
+
+ if (formats->type == -1) {
+ return NULL;
+ }
+
+ return formats;
+}
+
+
/* Returns the "real" size for a header, ie the size iTunes uses for it
* (padding included)
*/
@@ -280,21 +307,23 @@ init_header (iPodBuffer *buffer, gchar header_id[4], guint header_len)
return mh;
}
+
static int
-write_mhod_type_3 (enum iPodThumbnailType type, iPodBuffer *buffer)
+write_mhod_type_3 (Itdb_Image *image, iPodBuffer *buffer)
{
MhodHeaderArtworkType3 *mhod;
unsigned int total_bytes;
- char *filename;
int len;
gunichar2 *utf16;
int i;
+
+ g_assert (image->filename != NULL);
+
mhod = (MhodHeaderArtworkType3 *)init_header (buffer, "mhod",
sizeof (MhodHeaderArtworkType3));
if (mhod == NULL) {
return -1;
}
-
total_bytes = sizeof (MhodHeaderArtworkType3);
mhod->total_len = GINT_TO_LE (total_bytes);
/* Modify header length, since iTunes only puts the length of
@@ -303,35 +332,17 @@ write_mhod_type_3 (enum iPodThumbnailType type, iPodBuffer *buffer)
mhod->header_len = GINT_TO_LE (sizeof (MhodHeader));
mhod->type = GINT_TO_LE (3);
mhod->mhod_version = GINT_TO_LE (2);
- switch (type) {
- case ITDB_IMAGE_FULL_SCREEN:
- filename = g_strdup_printf (":F%04u_1.ithmb",
- IPOD_THUMBNAIL_FULL_SIZE_CORRELATION_ID);
- break;
- case ITDB_IMAGE_NOW_PLAYING:
- filename = g_strdup_printf (":F%04u_1.ithmb",
- IPOD_THUMBNAIL_NOW_PLAYING_CORRELATION_ID);
- break;
- default:
- g_assert_not_reached ();
- /* Set filename to NULL to shut gcc up when compiling with
- * glib 2.4
- */
- filename = NULL;
- }
- len = strlen (filename);
+ len = strlen (image->filename);
/* number of bytes of the string encoded in UTF-16 */
mhod->string_len = GINT_TO_LE (2*len);
/* Make sure we have enough free space to write the string */
if (ipod_buffer_maybe_grow (buffer, total_bytes + 2*len) != 0) {
- g_free (filename);
return -1;
}
- utf16 = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
- g_free (filename);
+ utf16 = g_utf8_to_utf16 (image->filename, -1, NULL, NULL, NULL);
if (utf16 == NULL) {
return -1;
}
@@ -349,7 +360,7 @@ write_mhod_type_3 (enum iPodThumbnailType type, iPodBuffer *buffer)
}
static int
-write_mhni (Itdb_Image *image, iPodBuffer *buffer)
+write_mhni (Itdb_Image *image, int correlation_id, iPodBuffer *buffer)
{
MhniHeader *mhni;
unsigned int total_bytes;
@@ -368,15 +379,7 @@ write_mhni (Itdb_Image *image, iPodBuffer *buffer)
total_bytes = GINT_FROM_LE (mhni->header_len);
mhni->total_len = GINT_TO_LE (total_bytes);
-
- switch (image->type) {
- case ITDB_IMAGE_NOW_PLAYING:
- mhni->correlation_id = GINT_TO_LE (IPOD_THUMBNAIL_NOW_PLAYING_CORRELATION_ID);
- break;
- case ITDB_IMAGE_FULL_SCREEN:
- mhni->correlation_id = GINT_TO_LE (IPOD_THUMBNAIL_FULL_SIZE_CORRELATION_ID);
- break;
- }
+ mhni->correlation_id = GINT_TO_LE (correlation_id);
mhni->image_width = GINT16_TO_LE (image->width);
mhni->image_height = GINT16_TO_LE (image->height);
mhni->image_size = GINT32_TO_LE (image->size);
@@ -386,7 +389,7 @@ write_mhni (Itdb_Image *image, iPodBuffer *buffer)
if (sub_buffer == NULL) {
return -1;
}
- bytes_written = write_mhod_type_3 (image->type, sub_buffer);
+ bytes_written = write_mhod_type_3 (image, sub_buffer);
ipod_buffer_destroy (sub_buffer);
if (bytes_written == -1) {
return -1;
@@ -404,7 +407,7 @@ write_mhni (Itdb_Image *image, iPodBuffer *buffer)
}
static int
-write_mhod (Itdb_Image *image, iPodBuffer *buffer)
+write_mhod (Itdb_Image *image, int correlation_id, iPodBuffer *buffer)
{
MhodHeader *mhod;
unsigned int total_bytes;
@@ -427,7 +430,7 @@ write_mhod (Itdb_Image *image, iPodBuffer *buffer)
if (sub_buffer == NULL) {
return -1;
}
- bytes_written = write_mhni (image, sub_buffer);
+ bytes_written = write_mhni (image, correlation_id, sub_buffer);
ipod_buffer_destroy (sub_buffer);
if (bytes_written == -1) {
return -1;
@@ -465,7 +468,8 @@ write_mhii (Itdb_Track *song, iPodBuffer *buffer)
for (it = song->thumbnails; it != NULL; it = it->next) {
iPodBuffer *sub_buffer;
Itdb_Image *thumb;
-
+ const IpodArtworkFormat *img_info;
+
mhii->num_children = GINT_TO_LE (num_children);
mhii->total_len = GINT_TO_LE (total_bytes);
sub_buffer = ipod_buffer_get_sub_buffer (buffer, total_bytes);
@@ -473,7 +477,12 @@ write_mhii (Itdb_Track *song, iPodBuffer *buffer)
return -1;
}
thumb = (Itdb_Image *)it->data;
- bytes_written = write_mhod (thumb, sub_buffer);
+ img_info = get_artwork_info (song->itdb->device, thumb->type);
+ if (img_info == NULL) {
+ return -1;
+ }
+ bytes_written = write_mhod (thumb, img_info->correlation_id,
+ sub_buffer);
ipod_buffer_destroy (sub_buffer);
if (bytes_written == -1) {
return -1;
@@ -548,27 +557,28 @@ write_mhla (Itdb_iTunesDB *db, iPodBuffer *buffer)
return GINT_FROM_LE (mhla->header_len);
}
+
+
static int
write_mhif (Itdb_iTunesDB *db, iPodBuffer *buffer, enum iPodThumbnailType type)
{
MhifHeader *mhif;
-
+ const IpodArtworkFormat *img_info;
+
mhif = (MhifHeader *)init_header (buffer, "mhif", sizeof (MhifHeader));
if (mhif == NULL) {
return -1;
}
mhif->total_len = mhif->header_len;
- switch (type) {
- case ITDB_IMAGE_FULL_SCREEN:
- mhif->correlation_id = GINT_TO_LE (IPOD_THUMBNAIL_FULL_SIZE_CORRELATION_ID);
- mhif->image_size = GINT_TO_LE (IPOD_THUMBNAIL_FULL_SIZE_SIZE);
- break;
- case ITDB_IMAGE_NOW_PLAYING:
- mhif->correlation_id = GINT_TO_LE (IPOD_THUMBNAIL_NOW_PLAYING_CORRELATION_ID);
- mhif->image_size = GINT_TO_LE (IPOD_THUMBNAIL_NOW_PLAYING_SIZE);
- break;
+
+ img_info = get_artwork_info (db->device, type);
+ if (img_info == NULL) {
+ return -1;
}
+ mhif->correlation_id = GINT_TO_LE (img_info->correlation_id);
+ mhif->image_size = GINT_TO_LE (img_info->height * img_info->width * 2);
+
dump_mhif (mhif);
return GINT_FROM_LE (mhif->header_len);
diff --git a/src/db-image-parser.c b/src/db-image-parser.c
index 0240654..d2f152c 100644
--- a/src/db-image-parser.c
+++ b/src/db-image-parser.c
@@ -47,9 +47,9 @@ unpack_RGB_565 (gushort *pixels, unsigned int bytes_len)
cur_pixel = GINT16_FROM_LE (pixels[i]);
/* Unpack pixels */
- result[3*i] = (pixels[i] & RED_MASK) >> RED_SHIFT;
- result[3*i+1] = (pixels[i] & GREEN_MASK) >> GREEN_SHIFT;
- result[3*i+2] = (pixels[i] & BLUE_MASK) >> BLUE_SHIFT;
+ result[3*i] = (cur_pixel & RED_MASK) >> RED_SHIFT;
+ result[3*i+1] = (cur_pixel & GREEN_MASK) >> GREEN_SHIFT;
+ result[3*i+2] = (cur_pixel & BLUE_MASK) >> BLUE_SHIFT;
/* Normalize color values so that they use a [0..255] range */
result[3*i] <<= (8 - RED_BITS);
@@ -131,46 +131,48 @@ itdb_image_get_rgb_data (Itdb_Image *image)
*/
}
-G_GNUC_INTERNAL char *
-ipod_image_get_ithmb_filename (const char *mount_point, gint correlation_id)
+static int
+image_type_from_corr_id (IpodDevice *ipod, int corr_id)
{
- char *paths[] = {"iPod_Control", "Artwork", NULL, NULL};
- char *filename;
+ const IpodArtworkFormat *formats;
- paths[2] = g_strdup_printf ("F%04u_1.ithmb", correlation_id);
- filename = itdb_resolve_path (mount_point, (const char **)paths);
- g_free (paths[2]);
- return filename;
+ if (ipod == NULL) {
+ return -1;
+ }
+
+ g_object_get (G_OBJECT (ipod), "artwork-formats", &formats, NULL);
+ if (formats == NULL) {
+ return -1;
+ }
+
+ while (formats->type != -1) {
+ if (formats->correlation_id == corr_id) {
+ return formats->type;
+ }
+ formats++;
+ }
+
+ return -1;
}
G_GNUC_INTERNAL Itdb_Image *
-ipod_image_new_from_mhni (MhniHeader *mhni, const char *mount_point)
+ipod_image_new_from_mhni (MhniHeader *mhni, Itdb_iTunesDB *db)
{
- Itdb_Image *img;
+ Itdb_Image *img;
img = g_new0 (Itdb_Image, 1);
if (img == NULL) {
return NULL;
}
- img->filename = ipod_image_get_ithmb_filename (mount_point,
- GINT_FROM_LE (mhni->correlation_id));
img->size = GUINT32_FROM_LE (mhni->image_size);
img->offset = GUINT32_FROM_LE (mhni->ithmb_offset);
img->width = GINT16_FROM_LE (mhni->image_width);
img->height = GINT16_FROM_LE (mhni->image_height);
- switch (mhni->correlation_id) {
- case IPOD_THUMBNAIL_FULL_SIZE_CORRELATION_ID:
- case IPOD_NANO_THUMBNAIL_FULL_SIZE_CORRELATION_ID:
- img->type = ITDB_IMAGE_FULL_SCREEN;
- break;
- case IPOD_THUMBNAIL_NOW_PLAYING_CORRELATION_ID:
- case IPOD_NANO_THUMBNAIL_NOW_PLAYING_CORRELATION_ID:
- img->type = ITDB_IMAGE_NOW_PLAYING;
- break;
- default:
- g_print ("Unrecognized image size: %ux%u\n",
- img->width, img->height);
+ img->type = image_type_from_corr_id (db->device, mhni->correlation_id);
+ if ((img->type != IPOD_COVER_SMALL) && (img->type != IPOD_COVER_LARGE)) {
+ g_warning ("Unexpected cover type in mhni: %ux%u (%d)\n",
+ img->width, img->height, mhni->correlation_id);
g_free (img);
return NULL;
}
diff --git a/src/db-image-parser.h b/src/db-image-parser.h
index 4c0002e..8cf082f 100644
--- a/src/db-image-parser.h
+++ b/src/db-image-parser.h
@@ -41,9 +41,7 @@
#define BLUE_MASK (((1 << BLUE_BITS)-1) << BLUE_SHIFT)
G_GNUC_INTERNAL Itdb_Image *ipod_image_new_from_mhni (MhniHeader *mhni,
- const char *mount_point);
-G_GNUC_INTERNAL char *ipod_image_get_ithmb_filename (const char *mount_point,
- gint correlation_id);
+ Itdb_iTunesDB *db);
G_GNUC_INTERNAL int itdb_write_ithumb_files (Itdb_iTunesDB *db,
const char *mount_point);
diff --git a/src/itdb.h b/src/itdb.h
index 4b16c08..5cd2ff6 100644
--- a/src/itdb.h
+++ b/src/itdb.h
@@ -309,10 +309,6 @@ typedef struct SPLRules
GList *rules;
} SPLRules;
-enum ItdbImageType {
- ITDB_IMAGE_FULL_SCREEN,
- ITDB_IMAGE_NOW_PLAYING
-};
/* This structure can represent two slightly different images:
@@ -328,7 +324,7 @@ enum ItdbImageType {
* on the iPod
*/
struct _Itdb_Image {
- enum ItdbImageType type;
+ int type;
char *filename;
guint32 offset;
guint32 size;
diff --git a/src/ithumb-writer.c b/src/ithumb-writer.c
index 95521b0..075a9dc 100644
--- a/src/ithumb-writer.c
+++ b/src/ithumb-writer.c
@@ -35,18 +35,10 @@
#include <string.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
-#define FULL_THUMB_SIDE_LEN 0x8c
-#define NOW_PLAYING_THUMB_SIDE_LEN 0x38
-
-#define IPOD_THUMBNAIL_FULL_SIZE_CORRELATION_ID 1016
-#define IPOD_THUMBNAIL_NOW_PLAYING_CORRELATION_ID 1017
-
struct _iThumbWriter {
off_t cur_offset;
FILE *f;
- guint correlation_id;
- enum ItdbImageType type;
- int size;
+ IpodArtworkFormat *img_info;
GHashTable *cache;
};
typedef struct _iThumbWriter iThumbWriter;
@@ -56,9 +48,8 @@ typedef struct _iThumbWriter iThumbWriter;
* here to specify which size we are interested in in case the pixbuf is non
* square
*/
-static void
-pack_RGB_565 (GdkPixbuf *pixbuf, int size,
- gushort **pixels565, unsigned int *bytes_len)
+static gushort *
+pack_RGB_565 (GdkPixbuf *pixbuf, int dst_width, int dst_height)
{
guchar *pixels;
gushort *result;
@@ -69,17 +60,15 @@ pack_RGB_565 (GdkPixbuf *pixbuf, int size,
gint w;
gint h;
- g_return_if_fail (pixels565 != NULL);
- *pixels565 = NULL;
- g_return_if_fail (bytes_len != NULL);
-
g_object_get (G_OBJECT (pixbuf),
"rowstride", &row_stride, "n-channels", &channels,
"height", &height, "width", &width,
"pixels", &pixels, NULL);
- g_return_if_fail ((width <= size) && (height <= size));
- result = g_malloc0 (size * size * 2);
-
+ g_return_val_if_fail ((width <= dst_width) && (height <= dst_height), NULL);
+ result = g_malloc0 (dst_width * dst_height * 2);
+ if (result == NULL) {
+ return NULL;
+ }
for (h = 0; h < height; h++) {
for (w = 0; w < width; w++) {
gint r;
@@ -95,12 +84,10 @@ pack_RGB_565 (GdkPixbuf *pixbuf, int size,
r = (r << RED_SHIFT) & RED_MASK;
g = (g << GREEN_SHIFT) & GREEN_MASK;
b = (b << BLUE_SHIFT) & BLUE_MASK;
- result[h*size + w] = (GINT16_TO_LE (r | g | b));
+ result[h*dst_width + w] = (GINT16_TO_LE (r | g | b));
}
}
-
- *pixels565 = result;
- *bytes_len = size * size * 2;
+ return result;
}
@@ -141,31 +128,28 @@ ithumb_writer_write_thumbnail (iThumbWriter *writer,
return NULL;
}
- thumb = gdk_pixbuf_new_from_file_at_size (filename, writer->size,
- writer->size, NULL);
+ thumb = gdk_pixbuf_new_from_file_at_size (filename,
+ writer->img_info->width,
+ writer->img_info->height,
+ NULL);
if (thumb == NULL) {
g_free (image);
return NULL;
}
- g_object_get (G_OBJECT (thumb), "height", &image->height, NULL);
- if (image->height > writer->size) {
- g_object_unref (thumb);
- thumb = gdk_pixbuf_new_from_file_at_size (filename,
- writer->size,
- writer->size,
- NULL);
- if (thumb == NULL) {
- g_free (image);
- return NULL;
- }
- }
g_object_get (G_OBJECT (thumb),
"height", &image->height,
"width", &image->width,
NULL);
image->offset = writer->cur_offset;
- image->type = writer->type;
- pack_RGB_565 (thumb, writer->size, &pixels, &image->size);
+ image->type = writer->img_info->type;
+ image->size = writer->img_info->width * writer->img_info->height * 2;
+ /* FIXME: under certain conditions (probably related to writer->offset
+ * getting too big), this should be :F%04u_2.ithmb and so on
+ */
+ image->filename = g_strdup_printf (":F%04u_1.ithmb",
+ writer->img_info->correlation_id);
+ pixels = pack_RGB_565 (thumb, writer->img_info->width,
+ writer->img_info->height);
g_object_unref (G_OBJECT (thumb));
if (pixels == NULL) {
g_free (image);
@@ -185,17 +169,21 @@ ithumb_writer_write_thumbnail (iThumbWriter *writer,
}
-#define FULL_THUMB_SIDE_LEN 0x8c
-#define NOW_PLAYING_THUMB_SIDE_LEN 0x38
-
-#define FULL_THUMB_CORRELATION_ID 1016
-#define NOW_PLAYING_THUMB_CORRELATION_ID 1017
+static char *
+ipod_image_get_ithmb_filename (const char *mount_point, gint correlation_id)
+{
+ char *paths[] = {"iPod_Control", "Artwork", NULL, NULL};
+ char *filename;
+ paths[2] = g_strdup_printf ("F%04u_1.ithmb", correlation_id);
+ filename = itdb_resolve_path (mount_point, (const char **)paths);
+ g_free (paths[2]);
+ return filename;
+}
static iThumbWriter *
-ithumb_writer_new (const char *mount_point, enum ItdbImageType type,
- int correlation_id, int size)
+ithumb_writer_new (const char *mount_point, const IpodArtworkFormat *info)
{
char *filename;
iThumbWriter *writer;
@@ -203,18 +191,23 @@ ithumb_writer_new (const char *mount_point, enum ItdbImageType type,
if (writer == NULL) {
return NULL;
}
- writer->correlation_id = correlation_id;
- writer->size = size;
- writer->type = type;
+ writer->img_info = g_memdup (info, sizeof (IpodArtworkFormat));
+ if (writer->img_info == NULL) {
+ g_free (writer);
+ return NULL;
+ }
writer->cache = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, NULL);
if (writer->cache == NULL) {
+ g_free (writer->img_info);
g_free (writer);
return NULL;
}
- filename = ipod_image_get_ithmb_filename (mount_point, correlation_id);
+ filename = ipod_image_get_ithmb_filename (mount_point,
+ info->correlation_id);
if (filename == NULL) {
g_hash_table_destroy (writer->cache);
+ g_free (writer->img_info);
g_free (writer);
return NULL;
}
@@ -223,6 +216,7 @@ ithumb_writer_new (const char *mount_point, enum ItdbImageType type,
g_print ("Error opening %s: %s\n", filename, strerror (errno));
g_free (filename);
g_hash_table_destroy (writer->cache);
+ g_free (writer->img_info);
g_free (writer);
return NULL;
}
@@ -236,38 +230,74 @@ ithumb_writer_free (iThumbWriter *writer)
{
g_return_if_fail (writer != NULL);
g_hash_table_destroy (writer->cache);
+ g_free (writer->img_info);
fclose (writer->f);
g_free (writer);
}
+
+static void
+write_thumbnail (gpointer data, gpointer user_data)
+{
+ iThumbWriter *writer;
+ Itdb_Track *song;
+ Itdb_Image *thumb;
+
+ song = (Itdb_Track *)user_data;
+ writer = (iThumbWriter *)data;
+
+ thumb = ithumb_writer_write_thumbnail (writer,
+ song->orig_image_filename);
+ if (thumb != NULL) {
+ song->thumbnails = g_list_append (song->thumbnails, thumb);
+ song->artwork_count++;
+ }
+}
+
+
G_GNUC_INTERNAL int
itdb_write_ithumb_files (Itdb_iTunesDB *db, const char *mount_point)
{
+ GList *writers;
GList *it;
- iThumbWriter *fullsize_writer;
- iThumbWriter *nowplaying_writer;
+ const IpodArtworkFormat *format;
/* g_print ("%s\n", G_GNUC_FUNCTION);*/
- fullsize_writer = ithumb_writer_new (mount_point,
- ITDB_IMAGE_FULL_SCREEN,
- FULL_THUMB_CORRELATION_ID,
- FULL_THUMB_SIDE_LEN);
- if (fullsize_writer == NULL) {
+
+ if (db->device == NULL) {
return -1;
}
- nowplaying_writer = ithumb_writer_new (mount_point,
- ITDB_IMAGE_NOW_PLAYING,
- NOW_PLAYING_THUMB_CORRELATION_ID,
- NOW_PLAYING_THUMB_SIDE_LEN);
- if (nowplaying_writer == NULL) {
- ithumb_writer_free (fullsize_writer);
+ g_object_get (G_OBJECT (db->device), "artwork-formats",
+ &format, NULL);
+ if (format == NULL) {
+ return -1;
+ }
+
+ writers = NULL;
+ while (format->type != -1) {
+ iThumbWriter *writer;
+
+ switch (format->type) {
+ case IPOD_COVER_SMALL:
+ case IPOD_COVER_LARGE:
+ writer = ithumb_writer_new (mount_point, format);
+ if (writer != NULL) {
+ writers = g_list_prepend (writers, writer);
+ }
+ break;
+ default:
+ break;
+ }
+ format++;
+ }
+
+ if (writers == NULL) {
return -1;
}
for (it = db->tracks; it != NULL; it = it->next) {
Itdb_Track *song;
- Itdb_Image *thumb;
song = (Itdb_Track *)it->data;
song->artwork_count = 0;
@@ -275,24 +305,11 @@ itdb_write_ithumb_files (Itdb_iTunesDB *db, const char *mount_point)
if (song->orig_image_filename == NULL) {
continue;
}
- thumb = ithumb_writer_write_thumbnail (nowplaying_writer,
- song->orig_image_filename);
- if (thumb != NULL) {
- song->thumbnails = g_list_append (song->thumbnails,
- thumb);
- song->artwork_count++;
- }
- thumb = ithumb_writer_write_thumbnail (fullsize_writer,
- song->orig_image_filename);
- if (thumb != NULL) {
- song->thumbnails = g_list_append (song->thumbnails,
- thumb);
- song->artwork_count++;
- }
+ g_list_foreach (writers, write_thumbnail, song);
}
- ithumb_writer_free (nowplaying_writer);
- ithumb_writer_free (fullsize_writer);
+ g_list_foreach (writers, (GFunc)ithumb_writer_free, NULL);
+ g_list_free (writers);
return 0;
}
diff --git a/tests/test-covers.c b/tests/test-covers.c
index 98d3575..fb21d00 100644
--- a/tests/test-covers.c
+++ b/tests/test-covers.c
@@ -114,13 +114,10 @@ save_song_thumbnails (Itdb_Track *song)
g_return_if_fail (image);
filename = NULL;
- if (image->type == ITDB_IMAGE_FULL_SCREEN) {
- filename = g_strdup_printf ("/tmp/fullsize%016"G_GINT64_MODIFIER"x.png",
- song->dbid);
- } else if (image->type == ITDB_IMAGE_NOW_PLAYING) {
- filename = g_strdup_printf ("/tmp/nowplaying%016"G_GINT64_MODIFIER"x.png",
- song->dbid);
- }
+ filename = g_strdup_printf ("/tmp/%s-%s-%s-%d-%016"G_GINT64_MODIFIER"x.png",
+ song->artist, song->album,
+ song->title, image->type,
+ song->dbid);
if (filename != NULL) {
save_itdb_image (image, filename);
g_free (filename);