summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjcsjcs <jcsjcs@f01d2545-417e-4e96-918e-98f8d0dbbcb6>2007-09-08 15:15:57 +0000
committerjcsjcs <jcsjcs@f01d2545-417e-4e96-918e-98f8d0dbbcb6>2007-09-08 15:15:57 +0000
commit05191832dcb41a90919db54274d355670003bf8e (patch)
treeda6b374c3c3d4184c85a743020bbda40465da3ae
parent18a26a488382f5b633f0bec9742f381ecd6cc9f8 (diff)
downloadlibgpod-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--ChangeLog25
-rw-r--r--docs/reference/tmpl/artwork.sgml4
-rw-r--r--src/db-artwork-parser.c10
-rw-r--r--src/db-image-parser.c5
-rw-r--r--src/db-image-parser.h36
-rw-r--r--src/itdb.h6
-rw-r--r--src/itdb_artwork.c286
-rw-r--r--src/itdb_device.c16
-rw-r--r--src/itdb_device.h14
-rw-r--r--src/ithumb-writer.c182
-rw-r--r--tests/test-covers.c5
11 files changed, 551 insertions, 38 deletions
diff --git a/ChangeLog b/ChangeLog
index d2b908c..c856429 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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);
diff --git a/src/itdb.h b/src/itdb.h
index fa3274c..aeae904 100644
--- a/src/itdb.h
+++ b/src/itdb.h
@@ -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);