From 413674fba5e513b11b0522fb5cc9356169f7c85d Mon Sep 17 00:00:00 2001 From: Christophe Fergeau Date: Wed, 23 Nov 2005 18:21:52 +0000 Subject: 2005-11-23 Christophe Fergeau * 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 --- ChangeLog | 19 ++++++ src/db-artwork-debug.c | 3 +- src/db-artwork-parser.c | 87 ++++++++++++++++-------- src/db-artwork-parser.h | 6 -- src/db-artwork-writer.c | 106 ++++++++++++++++------------- src/db-image-parser.c | 56 +++++++-------- src/db-image-parser.h | 4 +- src/itdb.h | 6 +- src/ithumb-writer.c | 177 ++++++++++++++++++++++++++---------------------- tests/test-covers.c | 11 ++- 10 files changed, 270 insertions(+), 205 deletions(-) diff --git a/ChangeLog b/ChangeLog index 26e4f3a..83cfd62 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +2005-11-23 Christophe Fergeau + + * 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 * src/hal-common.c: 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 #include -#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); -- cgit