diff options
author | jcsjcs <jcsjcs@f01d2545-417e-4e96-918e-98f8d0dbbcb6> | 2007-09-08 15:15:57 +0000 |
---|---|---|
committer | jcsjcs <jcsjcs@f01d2545-417e-4e96-918e-98f8d0dbbcb6> | 2007-09-08 15:15:57 +0000 |
commit | 05191832dcb41a90919db54274d355670003bf8e (patch) | |
tree | da6b374c3c3d4184c85a743020bbda40465da3ae | |
parent | 18a26a488382f5b633f0bec9742f381ecd6cc9f8 (diff) | |
download | libgpod-05191832dcb41a90919db54274d355670003bf8e.tar.gz libgpod-05191832dcb41a90919db54274d355670003bf8e.tar.xz libgpod-05191832dcb41a90919db54274d355670003bf8e.zip |
* src/db-image-parser.c
src/itdb_device.c
src/ithumb-writer.c
src/db-image-parser.h
src/itdb_device.h
src/itdb.h
src/itdb_artwork.c
tests/test-covers.c: added support to read and write coverart on
iPhones. New cover formats are: MEDIUM, XLARGE, XSMALL, SMEDIUM
-- should be renamed if function becomes clearer.
Introduced New image formats for the thumbnails
(THUMB_FORMAT_RGB555, THUMB_FORMAT_REC_RGB555). Coding/decoding
functions are pack_/unpack_RGB_555() and
pack_/unpack_REC_RGB_555().
Introduced possible padding for thumbnail files
(Itdb_ArtworkFormat).
* src/db-artwork-parser.c: make output filename unique.
git-svn-id: https://gtkpod.svn.sf.net/svnroot/gtkpod/libgpod/trunk@1691 f01d2545-417e-4e96-918e-98f8d0dbbcb6
-rw-r--r-- | ChangeLog | 25 | ||||
-rw-r--r-- | docs/reference/tmpl/artwork.sgml | 4 | ||||
-rw-r--r-- | src/db-artwork-parser.c | 10 | ||||
-rw-r--r-- | src/db-image-parser.c | 5 | ||||
-rw-r--r-- | src/db-image-parser.h | 36 | ||||
-rw-r--r-- | src/itdb.h | 6 | ||||
-rw-r--r-- | src/itdb_artwork.c | 286 | ||||
-rw-r--r-- | src/itdb_device.c | 16 | ||||
-rw-r--r-- | src/itdb_device.h | 14 | ||||
-rw-r--r-- | src/ithumb-writer.c | 182 | ||||
-rw-r--r-- | tests/test-covers.c | 5 |
11 files changed, 551 insertions, 38 deletions
@@ -1,4 +1,27 @@ -2007-09-4 Jorg Schuler <jcsjcs at users.sourceforge.net> +2007-09-08 Jorg Schuler <jcsjcs at users.sourceforge.net> + + * src/db-image-parser.c + src/itdb_device.c + src/ithumb-writer.c + src/db-image-parser.h + src/itdb_device.h + src/itdb.h + src/itdb_artwork.c + tests/test-covers.c: added support to read and write coverart on + iPhones. New cover formats are: MEDIUM, XLARGE, XSMALL, SMEDIUM + -- should be renamed if function becomes clearer. + + Introduced New image formats for the thumbnails + (THUMB_FORMAT_RGB555, THUMB_FORMAT_REC_RGB555). Coding/decoding + functions are pack_/unpack_RGB_555() and + pack_/unpack_REC_RGB_555(). + + Introduced possible padding for thumbnail files + (Itdb_ArtworkFormat). + + * src/db-artwork-parser.c: make output filename unique. + +2007-09-04 Jorg Schuler <jcsjcs at users.sourceforge.net> * itdb_itunesdb.c (itdb_get_control_dir): added support for iPhones diff --git a/docs/reference/tmpl/artwork.sgml b/docs/reference/tmpl/artwork.sgml index efc25fc..94f5baf 100644 --- a/docs/reference/tmpl/artwork.sgml +++ b/docs/reference/tmpl/artwork.sgml @@ -74,6 +74,10 @@ album/track artwork. For working with photos, see the @ITDB_THUMB_PHOTO_LARGE: @ITDB_THUMB_PHOTO_FULL_SCREEN: @ITDB_THUMB_PHOTO_TV_SCREEN: +@ITDB_THUMB_COVER_XLARGE: +@ITDB_THUMB_COVER_MEDIUM: +@ITDB_THUMB_COVER_MEDIUM2: +@ITDB_THUMB_COVER_SMALL2: <!-- ##### FUNCTION itdb_artwork_new ##### --> <para> diff --git a/src/db-artwork-parser.c b/src/db-artwork-parser.c index 9d3c05d..378130d 100644 --- a/src/db-artwork-parser.c +++ b/src/db-artwork-parser.c @@ -587,6 +587,11 @@ ipod_supports_cover_art (Itdb_Device *device) case ITDB_THUMB_PHOTO_FULL_SCREEN: case ITDB_THUMB_PHOTO_TV_SCREEN: break; + case ITDB_THUMB_COVER_XLARGE: + case ITDB_THUMB_COVER_MEDIUM: + case ITDB_THUMB_COVER_SMEDIUM: + case ITDB_THUMB_COVER_XSMALL: + break; } formats++; } @@ -620,6 +625,11 @@ ipod_supports_photos (Itdb_Device *device) case ITDB_THUMB_PHOTO_FULL_SCREEN: case ITDB_THUMB_PHOTO_TV_SCREEN: return TRUE; + case ITDB_THUMB_COVER_XLARGE: + case ITDB_THUMB_COVER_MEDIUM: + case ITDB_THUMB_COVER_SMEDIUM: + case ITDB_THUMB_COVER_XSMALL: + break; } formats++; } diff --git a/src/db-image-parser.c b/src/db-image-parser.c index 9130bdc..be28838 100644 --- a/src/db-image-parser.c +++ b/src/db-image-parser.c @@ -113,6 +113,11 @@ ipod_image_new_from_mhni (MhniHeader *mhni, Itdb_DB *db) corr_id = get_gint32_db (db, mhni->correlation_id); img->type = image_type_from_corr_id (device, corr_id); +#if DEBUG_ARTWORK + printf ("corr_id: %d, of: %6d sz: %6d, x: %3d, y: %3d, xpad: %3d, ypad: %3d\n", + corr_id, img->offset, img->size, img->width, img->height, img->horizontal_padding, img->vertical_padding); +#endif + if (img->type == -1) { g_warning (_("Unexpected image type in mhni: size: %ux%u (%d), offset: %d\n"), diff --git a/src/db-image-parser.h b/src/db-image-parser.h index f09e574..79f538e 100644 --- a/src/db-image-parser.h +++ b/src/db-image-parser.h @@ -31,17 +31,35 @@ #include "itdb_private.h" #include "itdb.h" -#define RED_BITS 5 -#define RED_SHIFT 11 -#define RED_MASK (((1 << RED_BITS)-1) << RED_SHIFT) +#define DEBUG_ARTWORK 0 -#define GREEN_BITS 6 -#define GREEN_SHIFT 5 -#define GREEN_MASK (((1 << GREEN_BITS)-1) << GREEN_SHIFT) +#define RED_BITS_565 5 +#define RED_SHIFT_565 11 +#define RED_MASK_565 (((1 << RED_BITS_565)-1) << RED_SHIFT_565) -#define BLUE_BITS 5 -#define BLUE_SHIFT 0 -#define BLUE_MASK (((1 << BLUE_BITS)-1) << BLUE_SHIFT) +#define GREEN_BITS_565 6 +#define GREEN_SHIFT_565 5 +#define GREEN_MASK_565 (((1 << GREEN_BITS_565)-1) << GREEN_SHIFT_565) + +#define BLUE_BITS_565 5 +#define BLUE_SHIFT_565 0 +#define BLUE_MASK_565 (((1 << BLUE_BITS_565)-1) << BLUE_SHIFT_565) + +#define ALPHA_BITS_555 1 +#define ALPHA_SHIFT_555 15 +#define ALPHA_MASK_555 (((1 << ALPHA_BITS_555)-1) << ALPHA_SHIFT_555) + +#define RED_BITS_555 5 +#define RED_SHIFT_555 10 +#define RED_MASK_555 (((1 << RED_BITS_555)-1) << RED_SHIFT_555) + +#define GREEN_BITS_555 5 +#define GREEN_SHIFT_555 5 +#define GREEN_MASK_555 (((1 << GREEN_BITS_555)-1) << GREEN_SHIFT_555) + +#define BLUE_BITS_555 5 +#define BLUE_SHIFT_555 0 +#define BLUE_MASK_555 (((1 << BLUE_BITS_555)-1) << BLUE_SHIFT_555) G_GNUC_INTERNAL Itdb_Thumb *ipod_image_new_from_mhni (MhniHeader *mhni, Itdb_DB *db); @@ -428,7 +428,11 @@ typedef enum { ITDB_THUMB_PHOTO_SMALL, ITDB_THUMB_PHOTO_LARGE, ITDB_THUMB_PHOTO_FULL_SCREEN, - ITDB_THUMB_PHOTO_TV_SCREEN + ITDB_THUMB_PHOTO_TV_SCREEN, + ITDB_THUMB_COVER_XLARGE, /* iPhone: cover flow */ + ITDB_THUMB_COVER_MEDIUM, /* iPhone: cover view */ + ITDB_THUMB_COVER_SMEDIUM, /* iPhone: ?? */ + ITDB_THUMB_COVER_XSMALL, /* iPhone: ?? */ } ItdbThumbType; diff --git a/src/itdb_artwork.c b/src/itdb_artwork.c index ebac51f..d176fe9 100644 --- a/src/itdb_artwork.c +++ b/src/itdb_artwork.c @@ -1,4 +1,4 @@ -/* Time-stamp: <2007-08-18 16:22:17 jcs> +/* Time-stamp: <2007-09-09 00:12:28 jcs> | | Copyright (C) 2002-2005 Jorg Schuler <jcsjcs at users sourceforge net> | Part of the gtkpod project. @@ -434,27 +434,217 @@ unpack_RGB_565 (guint16 *pixels, guint bytes_len, guint byte_order) guint i; g_return_val_if_fail (bytes_len < 2*(G_MAXUINT/3), NULL); + result = g_malloc ((bytes_len/2) * 3); - if (result == NULL) { - return NULL; + + for (i = 0; i < bytes_len/2; i++) { + guint16 cur_pixel; + /* FIXME: endianness */ + cur_pixel = get_gint16 (pixels[i], byte_order); + /* Unpack pixels */ + result[3*i] = (cur_pixel & RED_MASK_565) >> RED_SHIFT_565; + result[3*i+1] = (cur_pixel & GREEN_MASK_565) >> GREEN_SHIFT_565; + result[3*i+2] = (cur_pixel & BLUE_MASK_565) >> BLUE_SHIFT_565; + + /* Normalize color values so that they use a [0..255] range */ + result[3*i] <<= (8 - RED_BITS_565); + result[3*i+1] <<= (8 - GREEN_BITS_565); + result[3*i+2] <<= (8 - BLUE_BITS_565); + } + + return result; +} + +static guchar * +unpack_RGB_555 (guint16 *pixels, guint bytes_len, guint byte_order) +{ + guchar *result; + guint i; + + g_return_val_if_fail (bytes_len < 2*(G_MAXUINT/3), NULL); + + result = g_malloc ((bytes_len/2) * 3); + + for (i = 0; i < bytes_len/2; i++) { + guint16 cur_pixel; + /* FIXME: endianness */ + cur_pixel = get_gint16 (pixels[i], byte_order); + /* Unpack pixels */ + result[3*i] = (cur_pixel & RED_MASK_555) >> RED_SHIFT_555; + result[3*i+1] = (cur_pixel & GREEN_MASK_555) >> GREEN_SHIFT_555; + result[3*i+2] = (cur_pixel & BLUE_MASK_555) >> BLUE_SHIFT_555; + + /* Normalize color values so that they use a [0..255] range */ + result[3*i] <<= (8 - RED_BITS_555); + result[3*i+1] <<= (8 - GREEN_BITS_555); + result[3*i+2] <<= (8 - BLUE_BITS_555); + } + + return result; +} + + +static guint16 *rearrange_pixels (guint16 *pixels_s, guint16 *pixels_d, + gint width, gint height, gint row_stride) +{ + g_return_val_if_fail (width == height, pixels_d); + + if (pixels_d == NULL) + { + pixels_d = g_malloc0 (sizeof (guint16)*width*height); + } + + if (width == 1) + { + *pixels_d = *pixels_s; + } + else + { + rearrange_pixels (pixels_s + 0, + pixels_d + 0 + 0, + width/2, height/2, + row_stride); + rearrange_pixels (pixels_s + (width/2)*(height/2), + pixels_d + (height/2)*row_stride + 0, + width/2, height/2, + row_stride); + rearrange_pixels (pixels_s + 2*(width/2)*(height/2), + pixels_d + width/2, + width/2, height/2, + row_stride); + rearrange_pixels (pixels_s + 3*(width/2)*(height/2), + pixels_d + (height/2)*row_stride + width/2, + width/2, height/2, + row_stride); + } + + return pixels_d; +} + + +static guchar * +unpack_rec_RGB_555 (guint16 *pixels, guint bytes_len, guint byte_order, + gint width, gint height) +{ + guchar *result; + guint16 *use_pixels; + gboolean free_use_pixels = FALSE; + guint16 *pixels_arranged; + + guint i; + + g_return_val_if_fail (bytes_len < 2*(G_MAXUINT/3), NULL); + g_return_val_if_fail (2*width*height < G_MAXUINT, NULL); + g_return_val_if_fail (width==height, NULL); + + if (2*width*height > bytes_len) + { + use_pixels = g_malloc0 (2*width*height); + g_memmove (use_pixels, pixels, bytes_len); + free_use_pixels = TRUE; + } + else + { + use_pixels = pixels; + } + + pixels_arranged = rearrange_pixels (use_pixels, NULL, + width, height, width); + + if (pixels_arranged == NULL) + { + return NULL; + } + + result = g_malloc ((bytes_len/2) * 3); + + for (i = 0; i < bytes_len/2; i++) { + guint16 cur_pixel; + /* FIXME: endianness */ + cur_pixel = get_gint16 (pixels_arranged[i], byte_order); + /* Unpack pixels */ + result[3*i] = (cur_pixel & RED_MASK_555) >> RED_SHIFT_555; + result[3*i+1] = (cur_pixel & GREEN_MASK_555) >> GREEN_SHIFT_555; + result[3*i+2] = (cur_pixel & BLUE_MASK_555) >> BLUE_SHIFT_555; + + /* Normalize color values so that they use a [0..255] range */ + result[3*i] <<= (8 - RED_BITS_555); + result[3*i+1] <<= (8 - GREEN_BITS_555); + result[3*i+2] <<= (8 - BLUE_BITS_555); + } + + g_free (pixels_arranged); + if (free_use_pixels) + { + g_free (use_pixels); + } + + return result; +} + + +#if DEBUG_ARTWORK +static guchar * +unpack_experimental (guint16 *pixels, guint bytes_len, guint byte_order, + gint width, gint height) +{ + guchar *result; + guint16 *use_pixels; + gboolean free_use_pixels = FALSE; + guint16 *pixels_arranged = NULL; + + guint i; + + g_return_val_if_fail (bytes_len < 2*(G_MAXUINT/3), NULL); + g_return_val_if_fail (2*width*height < G_MAXUINT, NULL); + g_return_val_if_fail (width==height, NULL); + + if (2*width*height > bytes_len) + { + use_pixels = g_malloc0 (2*width*height); + g_memmove (use_pixels, pixels, bytes_len); + free_use_pixels = TRUE; } + else + { + use_pixels = pixels; + } + +/* pixels_arranged = rearrange_pixels (use_pixels, NULL, + width, height, width); + + if (pixels_arranged == NULL) + { + return NULL; + } +*/ + + result = g_malloc ((bytes_len/2) * 3); + for (i = 0; i < bytes_len/2; i++) { guint16 cur_pixel; /* FIXME: endianness */ cur_pixel = get_gint16 (pixels[i], byte_order); /* Unpack pixels */ - 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; + result[3*i] = (cur_pixel & RED_MASK_555) >> RED_SHIFT_555; + result[3*i+1] = (cur_pixel & GREEN_MASK_555) >> GREEN_SHIFT_555; + result[3*i+2] = (cur_pixel & BLUE_MASK_555) >> BLUE_SHIFT_555; /* Normalize color values so that they use a [0..255] range */ - result[3*i] <<= (8 - RED_BITS); - result[3*i+1] <<= (8 - GREEN_BITS); - result[3*i+2] <<= (8 - BLUE_BITS); + result[3*i] <<= (8 - RED_BITS_555); + result[3*i+1] <<= (8 - GREEN_BITS_555); + result[3*i+2] <<= (8 - BLUE_BITS_555); + } + + g_free (pixels_arranged); + if (free_use_pixels) + { + g_free (use_pixels); } return result; } +#endif /* limit8bit() and unpack_UYVY() adapted from imgconvert.c from the @@ -472,7 +662,8 @@ static gint limit8bit (float x) return x; } static guchar * -unpack_UYVY (guchar *yuvdata, gint bytes_len, gint width, gint height) +unpack_UYVY (guchar *yuvdata, gint bytes_len, guint byte_order, + gint width, gint height) { gint imgsize = width*3*height; guchar* rgbdata; @@ -485,6 +676,7 @@ unpack_UYVY (guchar *yuvdata, gint bytes_len, gint width, gint height) gint h = 0; g_return_val_if_fail (bytes_len < 2*(G_MAXUINT/3), NULL); +/* printf ("w=%d h=%d s=%d\n", width, height, bytes_len); */ g_return_val_if_fail (width * height * 2 == bytes_len, NULL); rgbdata = g_malloc(imgsize); @@ -598,6 +790,13 @@ get_pixel_data (Itdb_Device *device, Itdb_Thumb *thumb) static guchar * itdb_thumb_get_rgb_data (Itdb_Device *device, Itdb_Thumb *thumb) { +#if 0 + #include <unistd.h> + #include <fcntl.h> + static gint i=0; + int fd; + gchar *name; +#endif void *pixels_raw; guchar *pixels=NULL; const Itdb_ArtworkFormat *img_info; @@ -609,6 +808,14 @@ itdb_thumb_get_rgb_data (Itdb_Device *device, Itdb_Thumb *thumb) g_return_val_if_fail (img_info, NULL); pixels_raw = get_pixel_data (device, thumb); + +#if 0 + name = g_strdup_printf ("thumb_%03d.raw", i++); + fd = creat (name, S_IRWXU|S_IRWXG|S_IRWXO); + write (fd, pixels_raw, thumb->size); + close (fd); + g_free (name); +#endif if (pixels_raw == NULL) { return NULL; } @@ -625,8 +832,39 @@ itdb_thumb_get_rgb_data (Itdb_Device *device, Itdb_Thumb *thumb) pixels = unpack_RGB_565 (pixels_raw, thumb->size, itdb_thumb_get_byteorder (img_info->format)); break; - case THUMB_FORMAT_UYVY: + case THUMB_FORMAT_RGB555_LE_90: + case THUMB_FORMAT_RGB555_BE_90: + /* FIXME: actually the previous two might require + different treatment (used on iPod Photo for the full + screen photo thumbnail) */ + case THUMB_FORMAT_RGB555_LE: + case THUMB_FORMAT_RGB555_BE: + pixels = unpack_RGB_555 (pixels_raw, thumb->size, + itdb_thumb_get_byteorder (img_info->format)); + break; + case THUMB_FORMAT_REC_RGB555_LE_90: + case THUMB_FORMAT_REC_RGB555_BE_90: + /* FIXME: actually the previous two might require + different treatment (used on iPod Photo for the full + screen photo thumbnail) */ + case THUMB_FORMAT_REC_RGB555_LE: + case THUMB_FORMAT_REC_RGB555_BE: + pixels = unpack_rec_RGB_555 (pixels_raw, thumb->size, + itdb_thumb_get_byteorder (img_info->format), + img_info->width, img_info->height); + break; + case THUMB_FORMAT_EXPERIMENTAL_LE: + case THUMB_FORMAT_EXPERIMENTAL_BE: +#if DEBUG_ARTWORK + pixels = unpack_experimental (pixels_raw, thumb->size, + itdb_thumb_get_byteorder (img_info->format), + img_info->width, img_info->height); + break; +#endif + case THUMB_FORMAT_UYVY_LE: + case THUMB_FORMAT_UYVY_BE: pixels = unpack_UYVY (pixels_raw, thumb->size, + itdb_thumb_get_byteorder (img_info->format), img_info->width, img_info->height); break; } @@ -701,6 +939,14 @@ itdb_thumb_get_gdk_pixbuf (Itdb_Device *device, Itdb_Thumb *thumb) width = 220; height = 176; break; case ITDB_THUMB_PHOTO_TV_SCREEN: width = 720; height = 480; break; + case ITDB_THUMB_COVER_XLARGE: + width = 320; height = 320; break; + case ITDB_THUMB_COVER_MEDIUM: + width = 128; height = 128; break; + case ITDB_THUMB_COVER_SMEDIUM: + width = 88; height = 88; break; + case ITDB_THUMB_COVER_XSMALL: + width = 56; height = 56; break; } if (width == 0) { @@ -814,6 +1060,10 @@ itdb_thumb_get_gdk_pixbuf (Itdb_Device *device, Itdb_Thumb *thumb) if (pad_y + height > img_info->height) height = img_info->height - pad_y; +#if DEBUG_ARTWORK + printf ("px=%2d py=%2d x=%3d y=%3d\n", pad_x, pad_y, width, height); +#endif + pixbuf_sub = gdk_pixbuf_new_subpixbuf (pixbuf_full, pad_x, pad_y, width, height); @@ -903,14 +1153,24 @@ itdb_thumb_get_byteorder (const ItdbThumbFormat format) { switch (format) { + case THUMB_FORMAT_UYVY_LE: case THUMB_FORMAT_RGB565_LE: case THUMB_FORMAT_RGB565_LE_90: + case THUMB_FORMAT_RGB555_LE: + case THUMB_FORMAT_RGB555_LE_90: + case THUMB_FORMAT_REC_RGB555_LE: + case THUMB_FORMAT_REC_RGB555_LE_90: + case THUMB_FORMAT_EXPERIMENTAL_LE: return G_LITTLE_ENDIAN; + case THUMB_FORMAT_UYVY_BE: case THUMB_FORMAT_RGB565_BE: case THUMB_FORMAT_RGB565_BE_90: + case THUMB_FORMAT_RGB555_BE: + case THUMB_FORMAT_RGB555_BE_90: + case THUMB_FORMAT_REC_RGB555_BE: + case THUMB_FORMAT_REC_RGB555_BE_90: + case THUMB_FORMAT_EXPERIMENTAL_BE: return G_BIG_ENDIAN; - case THUMB_FORMAT_UYVY: - return -1; } g_return_val_if_reached (-1); } diff --git a/src/itdb_device.c b/src/itdb_device.c index cc78dcf..21d09dc 100644 --- a/src/itdb_device.c +++ b/src/itdb_device.c @@ -213,7 +213,7 @@ static const Itdb_ArtworkFormat ipod_photo_artwork_info[] = { {ITDB_THUMB_PHOTO_SMALL, 42, 30, 1009, THUMB_FORMAT_RGB565_LE}, {ITDB_THUMB_PHOTO_LARGE, 130, 88, 1015, THUMB_FORMAT_RGB565_LE}, {ITDB_THUMB_PHOTO_FULL_SCREEN,220, 176, 1013, THUMB_FORMAT_RGB565_BE_90}, - {ITDB_THUMB_PHOTO_TV_SCREEN, 720, 480, 1019, THUMB_FORMAT_UYVY}, + {ITDB_THUMB_PHOTO_TV_SCREEN, 720, 480, 1019, THUMB_FORMAT_UYVY_BE}, {-1, -1, -1, -1, -1} }; @@ -231,7 +231,7 @@ static const Itdb_ArtworkFormat ipod_video_artwork_info[] = { {ITDB_THUMB_PHOTO_SMALL, 50, 41, 1036, THUMB_FORMAT_RGB565_LE}, {ITDB_THUMB_PHOTO_LARGE, 130, 88, 1015, THUMB_FORMAT_RGB565_LE}, {ITDB_THUMB_PHOTO_FULL_SCREEN,320, 240, 1024, THUMB_FORMAT_RGB565_LE}, - {ITDB_THUMB_PHOTO_TV_SCREEN, 720, 480, 1019, THUMB_FORMAT_UYVY}, + {ITDB_THUMB_PHOTO_TV_SCREEN, 720, 480, 1019, THUMB_FORMAT_UYVY_BE}, {-1, -1, -1, -1, -1} }; @@ -241,6 +241,16 @@ static const Itdb_ArtworkFormat ipod_mobile_1_artwork_info[] = { {-1, -1, -1, -1, -1} }; +static const Itdb_ArtworkFormat ipod_iphone_1_artwork_info[] = { + {ITDB_THUMB_COVER_LARGE, 256, 256, 3001, THUMB_FORMAT_REC_RGB555_LE}, + {ITDB_THUMB_COVER_MEDIUM, 128, 128, 3002, THUMB_FORMAT_REC_RGB555_LE}, + {ITDB_THUMB_COVER_SMALL, 64, 64, 3003, THUMB_FORMAT_REC_RGB555_LE}, + {ITDB_THUMB_COVER_XLARGE, 320, 320, 3005, THUMB_FORMAT_RGB555_LE}, + {ITDB_THUMB_COVER_XSMALL, 56, 56, 3006, THUMB_FORMAT_RGB555_LE, 8192}, /*pad data to 8192 bytes */ + {ITDB_THUMB_COVER_SMEDIUM, 88, 88, 3007, THUMB_FORMAT_RGB555_LE, 16364}, /*pad data to 16384 bytes */ + {-1, -1, -1, -1, -1} +}; + /* This will be indexed using a value from the ITDB_IPOD_MODEL enum */ static const Itdb_ArtworkFormat *ipod_artwork_info_table[] = { @@ -266,7 +276,7 @@ static const Itdb_ArtworkFormat *ipod_artwork_info_table[] = { ipod_nano_artwork_info, /* Nano (Blue) */ ipod_nano_artwork_info, /* Nano (Green) */ ipod_nano_artwork_info, /* Nano (Pink) */ - NULL, /* iPhone (1) -- FIXME! */ + ipod_iphone_1_artwork_info,/* iPhone (1) */ NULL }; diff --git a/src/itdb_device.h b/src/itdb_device.h index bba6f48..2c11630 100644 --- a/src/itdb_device.h +++ b/src/itdb_device.h @@ -50,11 +50,22 @@ typedef enum _ItdbThumbFormat ItdbThumbFormat; enum _ItdbThumbFormat { - THUMB_FORMAT_UYVY, + THUMB_FORMAT_UYVY_LE, + THUMB_FORMAT_UYVY_BE, THUMB_FORMAT_RGB565_LE, THUMB_FORMAT_RGB565_LE_90, THUMB_FORMAT_RGB565_BE, THUMB_FORMAT_RGB565_BE_90, + THUMB_FORMAT_RGB555_LE, + THUMB_FORMAT_RGB555_LE_90, + THUMB_FORMAT_RGB555_BE, + THUMB_FORMAT_RGB555_BE_90, + THUMB_FORMAT_REC_RGB555_LE, + THUMB_FORMAT_REC_RGB555_LE_90, + THUMB_FORMAT_REC_RGB555_BE, + THUMB_FORMAT_REC_RGB555_BE_90, + THUMB_FORMAT_EXPERIMENTAL_LE, + THUMB_FORMAT_EXPERIMENTAL_BE, }; @@ -83,6 +94,7 @@ struct _Itdb_ArtworkFormat gint16 height; gint16 correlation_id; ItdbThumbFormat format; + gint32 padding; }; G_GNUC_INTERNAL const Itdb_ArtworkFormat *itdb_device_get_artwork_formats (Itdb_Device *device); diff --git a/src/ithumb-writer.c b/src/ithumb-writer.c index 562684b..e4d4a64 100644 --- a/src/ithumb-writer.c +++ b/src/ithumb-writer.c @@ -1,4 +1,4 @@ -/* Time-stamp: <2007-02-10 01:00:40 jcs> +/* Time-stamp: <2007-09-09 00:13:13 jcs> * * Copyright (C) 2005 Christophe Fergeau * @@ -103,12 +103,12 @@ pack_RGB_565 (GdkPixbuf *pixbuf, const Itdb_ArtworkFormat *img_info, g = pixels[h*row_stride + w*channels + 1]; b = pixels[h*row_stride + w*channels + 2]; - r >>= (8 - RED_BITS); - g >>= (8 - GREEN_BITS); - b >>= (8 - BLUE_BITS); - r = (r << RED_SHIFT) & RED_MASK; - g = (g << GREEN_SHIFT) & GREEN_MASK; - b = (b << BLUE_SHIFT) & BLUE_MASK; + r >>= (8 - RED_BITS_565); + g >>= (8 - GREEN_BITS_565); + b >>= (8 - BLUE_BITS_565); + r = (r << RED_SHIFT_565) & RED_MASK_565; + g = (g << GREEN_SHIFT_565) & GREEN_MASK_565; + b = (b << BLUE_SHIFT_565) & BLUE_MASK_565; result[line + w + horizontal_padding] = get_gint16 (r | g | b, byte_order); } @@ -116,6 +116,121 @@ pack_RGB_565 (GdkPixbuf *pixbuf, const Itdb_ArtworkFormat *img_info, return result; } +static guint16 * +pack_RGB_555 (GdkPixbuf *pixbuf, const Itdb_ArtworkFormat *img_info, + gint horizontal_padding, gint vertical_padding) +{ + guchar *pixels; + guint16 *result; + gint row_stride; + gint channels; + gint width; + gint height; + gint w; + gint h; + gint byte_order; + + g_object_get (G_OBJECT (pixbuf), + "rowstride", &row_stride, "n-channels", &channels, + "height", &height, "width", &width, + "pixels", &pixels, NULL); + g_return_val_if_fail ((width <= img_info->width) && (height <= img_info->height), NULL); + /* dst_width and dst_height come from a width/height database + * hardcoded in libipoddevice code, so dst_width * dst_height * 2 can't + * overflow, even on an iPod containing malicious data + */ + result = g_malloc0 (img_info->width * img_info->height * 2); + + byte_order = itdb_thumb_get_byteorder (img_info->format); + + for (h = 0; h < height; h++) { + gint line = (h+vertical_padding)*img_info->width; + for (w = 0; w < width; w++) { + gint r; + gint g; + gint b; + gint a; + + r = pixels[h*row_stride + w*channels]; + g = pixels[h*row_stride + w*channels + 1]; + b = pixels[h*row_stride + w*channels + 2]; + + r >>= (8 - RED_BITS_555); + g >>= (8 - GREEN_BITS_555); + b >>= (8 - BLUE_BITS_555); + a = (1 << ALPHA_SHIFT_555) & ALPHA_MASK_555; + r = (r << RED_SHIFT_555) & RED_MASK_555; + g = (g << GREEN_SHIFT_555) & GREEN_MASK_555; + b = (b << BLUE_SHIFT_555) & BLUE_MASK_555; + result[line + w + horizontal_padding] = + get_gint16 (a | r | g | b, byte_order); + /* I'm not sure if the highest bit really is + the alpha channel. For now I'm just setting + this bit because that's what I have seen. */ + } + } + return result; +} + + +static guint16 *derange_pixels (guint16 *pixels_s, guint16 *pixels_d, + gint width, gint height, gint row_stride) +{ + g_return_val_if_fail (width == height, pixels_s); + + if (pixels_s == NULL) + { + pixels_s = g_malloc0 (sizeof (guint16)*width*height); + } + + if (width == 1) + { + *pixels_s = *pixels_d; + } + else + { + derange_pixels (pixels_s + 0, + pixels_d + 0 + 0, + width/2, height/2, + row_stride); + derange_pixels (pixels_s + (width/2)*(height/2), + pixels_d + (height/2)*row_stride + 0, + width/2, height/2, + row_stride); + derange_pixels (pixels_s + 2*(width/2)*(height/2), + pixels_d + width/2, + width/2, height/2, + row_stride); + derange_pixels (pixels_s + 3*(width/2)*(height/2), + pixels_d + (height/2)*row_stride + width/2, + width/2, height/2, + row_stride); + } + + return pixels_s; +} + +static guint16 * +pack_rec_RGB_555 (GdkPixbuf *pixbuf, const Itdb_ArtworkFormat *img_info, + gint horizontal_padding, gint vertical_padding) +{ + guint16 *pixels; + guint16 *deranged_pixels = NULL; + + pixels = pack_RGB_555 (pixbuf, img_info, + horizontal_padding, vertical_padding); + + if (pixels) + { + deranged_pixels = derange_pixels (NULL, pixels, + img_info->width, img_info->height, + img_info->width); + g_free (pixels); + } + + return deranged_pixels; +} + /* pack_UYVY() is adapted from imgconvert.c from the GPixPod project * (www.gpixpod.org) */ @@ -424,6 +539,10 @@ ithumb_writer_write_thumbnail (iThumbWriter *writer, break; case ITDB_THUMB_COVER_LARGE: case ITDB_THUMB_COVER_SMALL: + case ITDB_THUMB_COVER_XLARGE: + case ITDB_THUMB_COVER_MEDIUM: + case ITDB_THUMB_COVER_SMEDIUM: + case ITDB_THUMB_COVER_XSMALL: thumb->filename = g_strdup_printf (":F%d_%d.ithmb", writer->img_info->correlation_id, writer->current_file_index); @@ -468,7 +587,33 @@ ithumb_writer_write_thumbnail (iThumbWriter *writer, thumb->horizontal_padding, thumb->vertical_padding); break; - case THUMB_FORMAT_UYVY: + case THUMB_FORMAT_RGB555_LE_90: + case THUMB_FORMAT_RGB555_BE_90: + /* FIXME: actually the previous two might require + different treatment (used on iPod Photo for the full + screen photo thumbnail) */ + case THUMB_FORMAT_RGB555_LE: + case THUMB_FORMAT_RGB555_BE: + pixels = pack_RGB_555 (pixbuf, writer->img_info, + thumb->horizontal_padding, + thumb->vertical_padding); + break; + case THUMB_FORMAT_REC_RGB555_LE_90: + case THUMB_FORMAT_REC_RGB555_BE_90: + /* FIXME: actually the previous two might require + different treatment (used on iPod Photo for the full + screen photo thumbnail) */ + case THUMB_FORMAT_REC_RGB555_LE: + case THUMB_FORMAT_REC_RGB555_BE: + pixels = pack_rec_RGB_555 (pixbuf, writer->img_info, + thumb->horizontal_padding, + thumb->vertical_padding); + break; + case THUMB_FORMAT_EXPERIMENTAL_LE: + case THUMB_FORMAT_EXPERIMENTAL_BE: + break; + case THUMB_FORMAT_UYVY_BE: + case THUMB_FORMAT_UYVY_LE: pixels = pack_UYVY (pixbuf, writer->img_info, thumb->horizontal_padding, thumb->vertical_padding); @@ -490,6 +635,23 @@ ithumb_writer_write_thumbnail (iThumbWriter *writer, g_free (pixels); writer->cur_offset += thumb->size; + if (writer->img_info->padding != 0) + { + gint padding = writer->img_info->padding - thumb->size; + g_return_val_if_fail (padding >= 0, TRUE); + if (padding != 0) + { + /* FIXME: check if a simple fseek() will do the same */ + gchar *pad_bytes = g_malloc0 (padding); + if (fwrite (pad_bytes, padding, 1, writer->f) != 1) { + g_free (pad_bytes); + g_print ("Error writing to file: %s\n", strerror (errno)); + return FALSE; + } + g_free (pad_bytes); + writer->cur_offset += padding; + } + } return TRUE; } @@ -949,6 +1111,10 @@ itdb_write_ithumb_files (Itdb_DB *db) iThumbWriter *writer; switch (format->type) { + case ITDB_THUMB_COVER_XLARGE: + case ITDB_THUMB_COVER_MEDIUM: + case ITDB_THUMB_COVER_SMEDIUM: + case ITDB_THUMB_COVER_XSMALL: case ITDB_THUMB_COVER_SMALL: case ITDB_THUMB_COVER_LARGE: case ITDB_THUMB_PHOTO_SMALL: diff --git a/tests/test-covers.c b/tests/test-covers.c index 0a79cff..53547d7 100644 --- a/tests/test-covers.c +++ b/tests/test-covers.c @@ -47,8 +47,8 @@ save_itdb_thumb (Itdb_iTunesDB *itdb, Itdb_Thumb *thumb, const char *filename) static void save_song_thumbnails (Itdb_Track *song) { + static gint count = 0; GList *it; - for (it = song->artwork->thumbnails; it != NULL; it = it->next) { Itdb_Thumb *thumb; gchar *filename; @@ -57,7 +57,8 @@ save_song_thumbnails (Itdb_Track *song) g_return_if_fail (thumb); filename = NULL; - filename = g_strdup_printf ("%s-%s-%s-%d-%016"G_GINT64_MODIFIER"x.png", + filename = g_strdup_printf ("%03d_%s-%s-%s-%d-%016"G_GINT64_MODIFIER"x.png", + count++, song->artist, song->album, song->title, thumb->type, song->dbid); |