diff options
author | Christophe Fergeau <teuf@gnome.org> | 2008-06-09 20:08:08 +0000 |
---|---|---|
committer | Christophe Fergeau <teuf@gnome.org> | 2008-06-09 20:08:08 +0000 |
commit | df22677b20d5b1a63787a0d8192dfa173eae881a (patch) | |
tree | 0f0b40be2ddcf5c9bf0766e0699bfcf93b545cad | |
parent | 4c372dc5f335213f559cfdce4c217736becb9b78 (diff) | |
download | libgpod-df22677b20d5b1a63787a0d8192dfa173eae881a.tar.gz libgpod-df22677b20d5b1a63787a0d8192dfa173eae881a.tar.xz libgpod-df22677b20d5b1a63787a0d8192dfa173eae881a.zip |
* src/itdb_device.h:
* src/itdb_sysinfo_extended_parser.c:
* src/ithumb-writer.c: use background color and alignement
information from SysInfoExtended if available
git-svn-id: https://gtkpod.svn.sf.net/svnroot/gtkpod/libgpod/trunk@2014 f01d2545-417e-4e96-918e-98f8d0dbbcb6
-rw-r--r-- | ChangeLog | 1 | ||||
-rw-r--r-- | src/itdb_device.h | 22 | ||||
-rw-r--r-- | src/itdb_sysinfo_extended_parser.c | 28 | ||||
-rw-r--r-- | src/ithumb-writer.c | 281 |
4 files changed, 235 insertions, 97 deletions
@@ -1,4 +1,3 @@ - 2008-06-09 Christophe Fergeau <teuf@gnome.org> * src/itdb_device.h: diff --git a/src/itdb_device.h b/src/itdb_device.h index 8e43366..c48acd3 100644 --- a/src/itdb_device.h +++ b/src/itdb_device.h @@ -95,20 +95,20 @@ struct _Itdb_Device }; struct _Itdb_ArtworkFormat { - gint16 format_id; - gint16 width; - gint16 height; - ItdbThumbFormat format; + gint16 format_id; + gint16 width; + gint16 height; + ItdbThumbFormat format; gint32 padding; /* not found in SysInfoExtended, added * for compatibility with hardcoded artwork formats */ - gboolean crop; - gint rotation; - guint back_color; + gboolean crop; + gint rotation; + guchar back_color[4]; - gint display_width; - gboolean interlaced; - gboolean align_row_bytes; - gint color_adjustment; + gint display_width; + gboolean interlaced; + gboolean align_row_bytes; + gint color_adjustment; gdouble gamma; gint associated_format; }; diff --git a/src/itdb_sysinfo_extended_parser.c b/src/itdb_sysinfo_extended_parser.c index b0e2fa5..8352682 100644 --- a/src/itdb_sysinfo_extended_parser.c +++ b/src/itdb_sysinfo_extended_parser.c @@ -407,16 +407,22 @@ set_pixel_format (Itdb_ArtworkFormat *img_spec, GHashTable *dict) static void set_back_color (Itdb_ArtworkFormat *img_spec, GHashTable *dict) { - char *back_color; - - img_spec->back_color = 0; - back_color = get_string (dict, "BackColor"); - if (back_color == NULL) { - return; - } - img_spec->back_color = strtoul (back_color, NULL, 16); - g_hash_table_remove (dict, "BackColor"); - g_free (back_color); + char *back_color_str; + guint back_color; + gchar i; + + memset (img_spec->back_color, 0, sizeof (img_spec->back_color));; + back_color_str = get_string (dict, "BackColor"); + if (back_color_str == NULL) { + return; + } + back_color = strtoul (back_color_str, NULL, 16); + for (i = 3; i >= 0; i--) { + img_spec->back_color[(guchar)i] = back_color & 0xff; + back_color = back_color >> 8; + } + g_hash_table_remove (dict, "BackColor"); + g_free (back_color_str); } static Itdb_ArtworkFormat *g_value_to_image_format (GValue *value) @@ -550,7 +556,7 @@ itdb_sysinfo_properties_get_chapter_image_formats (const SysInfoIpodProperties * G_GNUC_INTERNAL gboolean itdb_sysinfo_properties_supports_sparse_artwork (const SysInfoIpodProperties *props) { - g_return_val_if_fail (props != NULL, NULL); + g_return_val_if_fail (props != NULL, FALSE); return props->supports_sparse_artwork; } diff --git a/src/ithumb-writer.c b/src/ithumb-writer.c index aff2852..46acd70 100644 --- a/src/ithumb-writer.c +++ b/src/ithumb-writer.c @@ -68,6 +68,26 @@ struct _iThumbWriter { typedef struct _iThumbWriter iThumbWriter; +static guint16 get_RGB_565_pixel (const guchar *pixel, gint byte_order) +{ + gint r; + gint g; + gint b; + + r = pixel[0]; + g = pixel[1]; + b = pixel[2]; + + 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; + + return get_gint16 (r | g | b, byte_order); +} + static guint16 * pack_RGB_565 (GdkPixbuf *pixbuf, const Itdb_ArtworkFormat *img_info, gint horizontal_padding, gint vertical_padding, @@ -79,48 +99,100 @@ pack_RGB_565 (GdkPixbuf *pixbuf, const Itdb_ArtworkFormat *img_info, gint channels; gint width; gint height; - gint w; gint h; gint byte_order; + gint dest_width; 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); + + if ((img_info->align_row_bytes) && ((img_info->width % 2) != 0)) { + /* each pixel is 2 bytes, to align rows on 4 bytes boundaries, + * width must be a multiple of 2 */ + dest_width = img_info->width + 1; + } else { + dest_width = img_info->width; + } /* 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 */ - *thumb_size = img_info->width * img_info->height * 2; + *thumb_size = dest_width * img_info->height * 2; result = g_malloc0 (*thumb_size); byte_order = itdb_thumb_get_byteorder (img_info->format); + for (h = 0; h < vertical_padding; h++) { + gint w; + gint line = h * dest_width; + + for (w = 0 ; w < dest_width; w++) { + result[line + w] = get_RGB_565_pixel (img_info->back_color, + byte_order); + } + line += (height+vertical_padding)*dest_width; + for (w = 0 ; w < dest_width; w++) { + result[line + w] = get_RGB_565_pixel (img_info->back_color, + byte_order); + } + } + 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; - - 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_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); - } + gint line = (h+vertical_padding)*dest_width; + gint w; + for (w = 0; w < dest_width; w++) { + guint16 packed_pixel; + if (w < horizontal_padding) { + packed_pixel = get_RGB_565_pixel (img_info->back_color, + byte_order); + } else if (w >= horizontal_padding+width) { + packed_pixel = get_RGB_565_pixel (img_info->back_color, + byte_order); + } else { + guchar *cur_pixel; + + cur_pixel = &pixels[h*row_stride + w*channels]; + packed_pixel = get_RGB_565_pixel (cur_pixel, byte_order); + } + result[line + w] = packed_pixel; + } } return result; } +static guint16 get_RGB_555_pixel (const guchar *pixel, gint byte_order, + gboolean has_alpha) +{ + gint r; + gint g; + gint b; + gint a; + + r = pixel[0]; + g = pixel[1]; + b = pixel[2]; + if (has_alpha) { + a = pixel[3]; + } else { + /* 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. */ + a = 1; + } + + r >>= (8 - RED_BITS_555); + g >>= (8 - GREEN_BITS_555); + b >>= (8 - BLUE_BITS_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; + a = (a << ALPHA_SHIFT_555) & ALPHA_MASK_555; + + return get_gint16 (a | r | g | b, byte_order); +} + static guint16 * pack_RGB_555 (GdkPixbuf *pixbuf, const Itdb_ArtworkFormat *img_info, gint horizontal_padding, gint vertical_padding, @@ -132,54 +204,100 @@ pack_RGB_555 (GdkPixbuf *pixbuf, const Itdb_ArtworkFormat *img_info, gint channels; gint width; gint height; - gint w; gint h; gint byte_order; + gint dest_width; 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); + + if ((img_info->align_row_bytes) && ((img_info->width % 2) != 0)) { + /* each pixel is 2 bytes, to align rows on 4 bytes boundaries, + * width must be a multiple of 2 */ + dest_width = img_info->width + 1; + } else { + dest_width = img_info->width; + } + /* 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 */ - - *thumb_size = img_info->width * img_info->height * 2; + *thumb_size = dest_width * img_info->height * 2; result = g_malloc0 (*thumb_size); byte_order = itdb_thumb_get_byteorder (img_info->format); + for (h = 0; h < vertical_padding; h++) { + gint w; + gint line = h * dest_width; + + for (w = 0 ; w < dest_width; w++) { + result[line + w] = get_RGB_555_pixel (img_info->back_color, + byte_order, TRUE); + } + line += (height+vertical_padding)*dest_width; + for (w = 0 ; w < dest_width; w++) { + result[line + w] = get_RGB_555_pixel (img_info->back_color, + byte_order, TRUE); + } + } + 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. */ - } + gint line = (h+vertical_padding)*dest_width; + gint w; + for (w = 0; w < dest_width; w++) { + guint16 packed_pixel; + if (w < horizontal_padding) { + packed_pixel = get_RGB_555_pixel (img_info->back_color, + byte_order, TRUE); + } else if (w >= horizontal_padding+width) { + packed_pixel = get_RGB_555_pixel (img_info->back_color, + byte_order, TRUE); + } else { + guchar *cur_pixel; + + cur_pixel = &pixels[h*row_stride + w*channels]; + packed_pixel = get_RGB_555_pixel (cur_pixel, byte_order, + FALSE); + } + result[line + w] = packed_pixel; + } } return result; } +static guint16 get_RGB_888_pixel (const guchar *pixel, gint byte_order, + gboolean has_alpha) +{ + gint r; + gint g; + gint b; + gint a; + + r = pixel[0]; + g = pixel[1]; + b = pixel[2]; + if (has_alpha) { + a = pixel[3]; + } else { + /* 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. */ + a = 0xff; + } + r >>= (8 - RED_BITS_888); + g >>= (8 - GREEN_BITS_888); + b >>= (8 - BLUE_BITS_888); + r = (r << RED_SHIFT_888) & RED_MASK_888; + g = (g << GREEN_SHIFT_888) & GREEN_MASK_888; + b = (b << BLUE_SHIFT_888) & BLUE_MASK_888; + a = (a << ALPHA_SHIFT_888) & ALPHA_MASK_888; + + return get_gint32 (a | r | g | b, byte_order); +} static guint16 * pack_RGB_888 (GdkPixbuf *pixbuf, const Itdb_ArtworkFormat *img_info, @@ -192,7 +310,6 @@ pack_RGB_888 (GdkPixbuf *pixbuf, const Itdb_ArtworkFormat *img_info, gint channels; gint width; gint height; - gint w; gint h; gint byte_order; @@ -210,31 +327,41 @@ pack_RGB_888 (GdkPixbuf *pixbuf, const Itdb_ArtworkFormat *img_info, byte_order = itdb_thumb_get_byteorder (img_info->format); + for (h = 0; h < vertical_padding; h++) { + gint w; + gint line = h * img_info->width; + + for (w = 0 ; w < img_info->width; w++) { + result[line + w] = get_RGB_888_pixel (img_info->back_color, + byte_order, TRUE); + } + line += (height+vertical_padding)*img_info->width; + for (w = 0 ; w < img_info->width; w++) { + result[line + w] = get_RGB_888_pixel (img_info->back_color, + byte_order, TRUE); + } + } + for (h = 0; h < height; h++) { - gint line = (h+vertical_padding)*img_info->width; - for (w = 0; w < width; w++) { - guint32 r; - guint32 g; - guint32 b; - guint32 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_888); - g >>= (8 - GREEN_BITS_888); - b >>= (8 - BLUE_BITS_888); - a = (0xff << ALPHA_SHIFT_888) & ALPHA_MASK_888; - r = (r << RED_SHIFT_888) & RED_MASK_888; - g = (g << GREEN_SHIFT_888) & GREEN_MASK_888; - b = (b << BLUE_SHIFT_888) & BLUE_MASK_888; - result[line + w + horizontal_padding] = - get_gint32 (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 - these bits because that's what I have seen. */ - } + gint line = (h+vertical_padding)*img_info->width; + gint w; + for (w = 0; w < img_info->width; w++) { + guint16 packed_pixel; + if (w < horizontal_padding) { + packed_pixel = get_RGB_888_pixel (img_info->back_color, + byte_order, TRUE); + } else if (w >= horizontal_padding+width) { + packed_pixel = get_RGB_888_pixel (img_info->back_color, + byte_order, TRUE); + } else { + guchar *cur_pixel; + + cur_pixel = &pixels[h*row_stride + w*channels]; + packed_pixel = get_RGB_888_pixel (cur_pixel, byte_order, + FALSE); + } + result[line + w] = packed_pixel; + } } return (guint16 *)result; } @@ -291,9 +418,15 @@ pack_rec_RGB_555 (GdkPixbuf *pixbuf, const Itdb_ArtworkFormat *img_info, if (pixels) { + gint row_stride; + if ((img_info->align_row_bytes) && ((img_info->width % 2) != 0)) { + row_stride = img_info->width + 1; + } else { + row_stride = img_info->width; + } deranged_pixels = derange_pixels (NULL, pixels, img_info->width, img_info->height, - img_info->width); + row_stride); g_free (pixels); } |