/*
| Copyright (C) 2007 Christophe Fergeau <teuf at gnome org>
| Part of the gtkpod project.
|
| URL: http://www.gtkpod.org/
| URL: http://gtkpod.sourceforge.net/
|
| The code contained in this file is free software; you can redistribute
| it and/or modify it under the terms of the GNU Lesser General Public
| License as published by the Free Software Foundation; either version
| 2.1 of the License, or (at your option) any later version.
|
| This file is distributed in the hope that it will be useful,
| but WITHOUT ANY WARRANTY; without even the implied warranty of
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
| Lesser General Public License for more details.
|
| You should have received a copy of the GNU Lesser General Public
| License along with this code; if not, write to the Free Software
| Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
| iTunes and iPod are trademarks of Apple
|
| This product is not supported/written/published by Apple!
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <glib/gi18n-lib.h>
#include "itdb_private.h"
#include "itdb_thumb.h"
#ifdef HAVE_GDKPIXBUF
#include <gdk-pixbuf/gdk-pixbuf.h>
#endif
Itdb_Thumb *itdb_thumb_new_from_file (const gchar *filename)
{
Itdb_Thumb_File *thumb_file;
Itdb_Thumb *thumb;
thumb_file = g_new0 (Itdb_Thumb_File, 1);
thumb = (Itdb_Thumb *)thumb_file;
thumb->data_type = ITDB_THUMB_TYPE_FILE;
thumb_file->filename = g_strdup (filename);
return thumb;
}
Itdb_Thumb *itdb_thumb_new_from_data (const guchar *data, gsize len)
{
Itdb_Thumb_Memory *thumb_memory;
Itdb_Thumb *thumb;
thumb_memory = g_new0 (Itdb_Thumb_Memory, 1);
thumb = (Itdb_Thumb *)thumb_memory;
thumb->data_type = ITDB_THUMB_TYPE_MEMORY;
thumb_memory->image_data = g_memdup (data, len);
thumb_memory->image_data_len = len;
return thumb;
}
#ifdef HAVE_GDKPIXBUF
Itdb_Thumb *itdb_thumb_new_from_pixbuf (gpointer pixbuf)
{
Itdb_Thumb_Pixbuf *thumb_pixbuf;
Itdb_Thumb *thumb;
thumb_pixbuf = g_new0 (Itdb_Thumb_Pixbuf, 1);
thumb = (Itdb_Thumb *)thumb_pixbuf;
thumb->data_type = ITDB_THUMB_TYPE_PIXBUF;
thumb_pixbuf->pixbuf = g_object_ref (G_OBJECT (pixbuf));
return thumb;
}
#else
Itdb_Thumb *itdb_thumb_new_from_pixbuf (gpointer pixbuf)
{
return NULL;
}
#endif
Itdb_Thumb_Ipod_Item *itdb_thumb_new_item_from_ipod (const Itdb_ArtworkFormat *format)
{
Itdb_Thumb_Ipod_Item *thumb_ipod;
thumb_ipod = g_new0 (Itdb_Thumb_Ipod_Item, 1);
thumb_ipod->format = format;
return thumb_ipod;
}
G_GNUC_INTERNAL Itdb_Thumb *itdb_thumb_ipod_new (void)
{
Itdb_Thumb *thumb;
thumb = (Itdb_Thumb *)g_new0 (Itdb_Thumb_Ipod, 1);
thumb->data_type = ITDB_THUMB_TYPE_IPOD;
return thumb;
}
static void itdb_thumb_ipod_item_free (Itdb_Thumb_Ipod_Item *item)
{
g_free (item->filename);
g_free (item);
}
/**
* itdb_thumb_free:
* @thumb: an #Itdb_Thumb
*
* Frees the memory used by @thumb
*
* Since: 0.3.0
*/
void itdb_thumb_free (Itdb_Thumb *thumb)
{
g_return_if_fail (thumb);
switch (thumb->data_type) {
case ITDB_THUMB_TYPE_FILE: {
Itdb_Thumb_File *thumb_file = (Itdb_Thumb_File *)thumb;
g_free (thumb_file->filename);
break;
}
case ITDB_THUMB_TYPE_MEMORY: {
Itdb_Thumb_Memory *thumb_memory = (Itdb_Thumb_Memory *)thumb;
g_free (thumb_memory->image_data);
break;
}
#ifdef HAVE_GDKPIXBUF
case ITDB_THUMB_TYPE_PIXBUF: {
Itdb_Thumb_Pixbuf *thumb_pixbuf = (Itdb_Thumb_Pixbuf *)thumb;
if (thumb_pixbuf->pixbuf) {
g_object_unref (G_OBJECT (thumb_pixbuf->pixbuf));
}
break;
}
#else
case ITDB_THUMB_TYPE_PIXBUF:
g_assert_not_reached();
#endif
case ITDB_THUMB_TYPE_IPOD: {
Itdb_Thumb_Ipod *thumb_ipod = (Itdb_Thumb_Ipod *)thumb;
g_list_foreach (thumb_ipod->thumbs,
(GFunc)itdb_thumb_ipod_item_free,
NULL);
g_list_free (thumb_ipod->thumbs);
break;
}
case ITDB_THUMB_TYPE_INVALID:
g_assert_not_reached ();
}
g_free (thumb);
}
static Itdb_Thumb_Ipod_Item *
itdb_thumb_ipod_item_duplicate (Itdb_Thumb_Ipod_Item *item)
{
Itdb_Thumb_Ipod_Item *new_item;
g_return_val_if_fail (item != NULL, NULL);
new_item = itdb_thumb_new_item_from_ipod (item->format);
new_item->filename = g_strdup (item->filename);
new_item->offset = item->offset;
new_item->size = item->size;
new_item->width = item->width;
new_item->height = item->height;
new_item->horizontal_padding = item->horizontal_padding;
new_item->vertical_padding = item->vertical_padding;
return new_item;
}
/**
* itdb_thumb_duplicate:
* @thumb: an #Itdb_Thumb
*
* Duplicates the data contained in @thumb
*
* Returns: a newly allocated copy of @thumb to be freed with
* itdb_thumb_free() after use
*
* Since: 0.3.0
*/
Itdb_Thumb *itdb_thumb_duplicate (Itdb_Thumb *thumb)
{
switch (thumb->data_type) {
case ITDB_THUMB_TYPE_FILE: {
Itdb_Thumb_File *thumb_file = (Itdb_Thumb_File *)thumb;
return itdb_thumb_new_from_file (thumb_file->filename);
}
case ITDB_THUMB_TYPE_MEMORY: {
Itdb_Thumb_Memory *thumb_memory = (Itdb_Thumb_Memory *)thumb;
return itdb_thumb_new_from_data (thumb_memory->image_data,
thumb_memory->image_data_len);
}
#ifdef HAVE_GDKPIXBUF
case ITDB_THUMB_TYPE_PIXBUF: {
Itdb_Thumb_Pixbuf *thumb_pixbuf = (Itdb_Thumb_Pixbuf *)thumb;
return itdb_thumb_new_from_pixbuf (thumb_pixbuf->pixbuf);
}
#else
case ITDB_THUMB_TYPE_PIXBUF:
return NULL;
#endif
case ITDB_THUMB_TYPE_IPOD: {
Itdb_Thumb_Ipod *thumb_ipod = (Itdb_Thumb_Ipod *)thumb;
Itdb_Thumb_Ipod *new_thumb;
GList *it;
new_thumb = (Itdb_Thumb_Ipod *)itdb_thumb_ipod_new ();
for (it = thumb_ipod->thumbs; it != NULL; it = it->next) {
Itdb_Thumb_Ipod_Item *item;
item = itdb_thumb_ipod_item_duplicate (it->data);
if (item != NULL) {
itdb_thumb_ipod_add (new_thumb, item);
}
}
new_thumb->thumbs = g_list_reverse (new_thumb->thumbs);
return (Itdb_Thumb *)new_thumb;
}
case ITDB_THUMB_TYPE_INVALID:
g_assert_not_reached ();
}
return NULL;
}
G_GNUC_INTERNAL gint
itdb_thumb_get_byteorder (const ItdbThumbFormat format)
{
switch (format)
{
case THUMB_FORMAT_UYVY_LE:
case THUMB_FORMAT_I420_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_RGB888_LE:
case THUMB_FORMAT_RGB888_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_I420_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_RGB888_BE:
case THUMB_FORMAT_RGB888_BE_90:
case THUMB_FORMAT_REC_RGB555_BE:
case THUMB_FORMAT_REC_RGB555_BE_90:
case THUMB_FORMAT_EXPERIMENTAL_BE:
return G_BIG_ENDIAN;
}
g_return_val_if_reached (-1);
}
guint itdb_thumb_get_rotation (Itdb_Thumb *thumb)
{
return thumb->rotation;
}
void itdb_thumb_set_rotation (Itdb_Thumb *thumb, guint rotation)
{
thumb->rotation = rotation;
}
G_GNUC_INTERNAL void itdb_thumb_ipod_add (Itdb_Thumb_Ipod *thumbs,
Itdb_Thumb_Ipod_Item *thumb)
{
thumbs->thumbs = g_list_prepend (thumbs->thumbs, thumb);
}
Itdb_Thumb_Ipod_Item *itdb_thumb_ipod_get_item_by_type (Itdb_Thumb *thumbs,
const Itdb_ArtworkFormat *format)
{
GList *gl;
g_return_val_if_fail (format != NULL, NULL);
g_return_val_if_fail (thumbs != NULL, NULL);
g_return_val_if_fail (thumbs->data_type == ITDB_THUMB_TYPE_IPOD, NULL);
for (gl=((Itdb_Thumb_Ipod *)thumbs)->thumbs; gl != NULL; gl=gl->next)
{
Itdb_Thumb_Ipod_Item *item = gl->data;
g_return_val_if_fail (item != NULL, NULL);
if (item->format == format) return item;
}
return NULL;
}
/**
* itdb_thumb_ipod_get_filename:
* @device: an #Itdb_Device
* @thumb: an #Itdb_Thumb_Ipod_Item
*
* Get filename of thumbnail. If it's a thumbnail on the iPod, return
* the full path to the ithmb file. Otherwise return the full path to
* the original file.
*
* Returns: newly allocated string containing the absolute path to the
* thumbnail file.
*/
gchar *itdb_thumb_ipod_get_filename (Itdb_Device *device, Itdb_Thumb_Ipod_Item *item)
{
gchar *artwork_dir;
char *filename = NULL;
g_return_val_if_fail (device, NULL);
g_return_val_if_fail (item, NULL);
if (strlen (item->filename) < 2) {
g_print (_("Illegal filename: '%s'.\n"), item->filename);
return NULL;
}
if (!device->mountpoint) {
g_print (_("Mountpoint not set.\n"));
return NULL;
}
artwork_dir = itdb_get_artwork_dir (device->mountpoint);
if (artwork_dir) {
filename = itdb_get_path (artwork_dir, item->filename+1);
g_free (artwork_dir);
}
/* FIXME: Hack */
if( !filename ) {
artwork_dir = itdb_get_photos_thumb_dir (device->mountpoint);
if (artwork_dir) {
const gchar *name_on_disk = strchr (item->filename+1, ':');
if (name_on_disk) {
filename = itdb_get_path (artwork_dir, name_on_disk + 1);
}
g_free (artwork_dir);
}
}
return filename;
}
const GList *itdb_thumb_ipod_get_thumbs (Itdb_Thumb_Ipod *thumbs)
{
return thumbs->thumbs;
}
#ifdef HAVE_GDKPIXBUF
/**
* itdb_thumb_to_pixbuf_at_size:
* @device: an #Itdb_Device
* @thumb: an #Itdb_Thumb
* @width: width of the pixbuf to retrieve, -1 for the biggest
* possible size and 0 for the smallest possible size (with no scaling)
* @height: height of the pixbuf to retrieve, -1 for the biggest possible size
* and 0 for the smallest possible size (with no scaling)
*
* Converts @thumb to a #GdkPixbuf.
*
* <note>
* Since we want to have gdk-pixbuf dependency optional, a generic
* gpointer is returned which you have to cast to a #GdkPixbuf using
* GDK_PIXBUF() yourself.
* </note>
*
* Returns: a #GdkPixbuf that must be unreffed with g_object_unref()
* after use, or NULL if the creation of the gdk-pixbuf failed or if
* libgpod was compiled without gdk-pixbuf support.
*
* Since: 0.7.0
*/
gpointer itdb_thumb_to_pixbuf_at_size (Itdb_Device *device, Itdb_Thumb *thumb,
gint width, gint height)
{
GdkPixbuf *pixbuf=NULL;
switch (thumb->data_type)
{
case ITDB_THUMB_TYPE_FILE:
{
Itdb_Thumb_File *thumb_file = (Itdb_Thumb_File *)thumb;
if ((width != -1) && (height !=-1) && (width != 0) && (height != 0))
{ /* scale */
pixbuf = gdk_pixbuf_new_from_file_at_size (thumb_file->filename,
width, height,
NULL);
}
else
{ /* don't scale */
pixbuf = gdk_pixbuf_new_from_file (thumb_file->filename, NULL);
}
break;
}
case ITDB_THUMB_TYPE_MEMORY:
{
Itdb_Thumb_Memory *thumb_mem = (Itdb_Thumb_Memory *)thumb;
GdkPixbufLoader *loader = gdk_pixbuf_loader_new ();
g_return_val_if_fail (loader, FALSE);
if ((width != -1) && (height !=-1) && (width != 0) && (height != 0))
{
gdk_pixbuf_loader_set_size (loader, width, height);
}
gdk_pixbuf_loader_write (loader,
thumb_mem->image_data,
thumb_mem->image_data_len,
NULL);
gdk_pixbuf_loader_close (loader, NULL);
pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
if (pixbuf)
g_object_ref (pixbuf);
g_object_unref (loader);
break;
}
case ITDB_THUMB_TYPE_PIXBUF:
{
Itdb_Thumb_Pixbuf *thumb_pixbuf = (Itdb_Thumb_Pixbuf*)thumb;
if ((width != -1) && (height !=-1) && (width != 0) && (height != 0))
{
pixbuf = gdk_pixbuf_scale_simple (thumb_pixbuf->pixbuf,
width, height,
GDK_INTERP_BILINEAR);
}
else
{
pixbuf = g_object_ref (thumb_pixbuf->pixbuf);
}
break;
}
case ITDB_THUMB_TYPE_IPOD:
{
Itdb_Thumb_Ipod *thumb_ipod = (Itdb_Thumb_Ipod *)thumb;
const GList *it;
Itdb_Thumb_Ipod_Item *chosen;
gint w=width;
gint h=height;
if ((width == -1) || (height == -1))
{ /* choose the largest available thumbnail */
w = G_MAXINT;
h = G_MAXINT;
}
if (device == NULL) {
/* device is needed to get the ipod mountpoint */
return NULL;
}
chosen = NULL;
for (it = itdb_thumb_ipod_get_thumbs (thumb_ipod);
it != NULL;
it = it->next) {
Itdb_Thumb_Ipod_Item *item = (Itdb_Thumb_Ipod_Item*)it->data;
if (chosen == NULL)
{ /* make sure we select *something* */
chosen = item;
}
if ((chosen->width > w) && (chosen->height > h))
{ /* try to find a thumb in size between the chosen and
the current one */
if ((item->width >= w) && (item->height >= h))
{
if ((item->width < chosen->width) || (item->height < chosen->height))
{
chosen = item;
}
}
}
if ((chosen->width < w) || (chosen->height < h))
{ /* try to find something bigger */
if ((item->width > chosen->width) || (item->height > chosen->height))
{
chosen = item;
}
}
}
if (chosen != NULL)
{
GdkPixbuf *pix = itdb_thumb_ipod_item_to_pixbuf (device, chosen);
if ((width != -1) && (height !=-1) && (width != 0) && (height != 0))
{ /* scale */
gdouble scalex = (gdouble)width/chosen->width;
gdouble scaley = (gdouble)height/chosen->height;
gdouble scale = MIN (scalex, scaley);
pixbuf = gdk_pixbuf_scale_simple (pix,
chosen->width*scale,
chosen->height*scale,
GDK_INTERP_BILINEAR);
g_object_unref (pix);
}
else
{ /* don't scale */
pixbuf = pix;
}
}
break;
}
case ITDB_THUMB_TYPE_INVALID:
g_return_val_if_reached (NULL);
} /* switch (...) */
return pixbuf;
}
static GList *itdb_thumb_ipod_to_pixbufs (Itdb_Device *device,
Itdb_Thumb_Ipod *thumb)
{
const GList *items;
GList *pixbufs = NULL;
g_return_val_if_fail (thumb != NULL, NULL);
g_return_val_if_fail (thumb->parent.data_type == ITDB_THUMB_TYPE_IPOD, NULL);
for (items = itdb_thumb_ipod_get_thumbs (thumb);
items != NULL;
items = items->next) {
GdkPixbuf *pixbuf;
pixbuf = itdb_thumb_ipod_item_to_pixbuf (device, items->data);
if (pixbuf != NULL) {
pixbufs = g_list_prepend (pixbufs, pixbuf);
}
}
return pixbufs;
}
/**
* itdb_thumb_to_pixbufs:
* @device: an #Itdb_Device
* @thumb: an #Itdb_Thumb
*
* Converts @thumb to a #GList of #GdkPixbuf. The returned #GList will
* generally contain only 1 element, the full-size pixbuf associated with
* @thumb, but when the artwork has been read from the ipod and hasn't been
* modified from the library, then the returned #GList will contain several
* #GdkPixbuf corresponding to the various thumbnail sizes that were
* written to the iPod database.
*
* Returns: a #GList of #GdkPixbuf which are associated with @thumb, NULL
* if the pixbuf was invalid or if libgpod is compiled without gdk-pixbuf
* support. The #GdkPixbuf must be unreffed with g_object_unref() after use
* and the #GList must be freed with g_list_free().
*
* Since: 0.7.0
*/
GList *itdb_thumb_to_pixbufs (Itdb_Device *device, Itdb_Thumb *thumb)
{
GList *pixbufs = NULL;
GdkPixbuf *pixbuf;
switch (thumb->data_type) {
case ITDB_THUMB_TYPE_IPOD:
pixbufs = itdb_thumb_ipod_to_pixbufs (device, (Itdb_Thumb_Ipod *)thumb);
break;
case ITDB_THUMB_TYPE_FILE:
case ITDB_THUMB_TYPE_MEMORY:
case ITDB_THUMB_TYPE_PIXBUF:
pixbuf = itdb_thumb_to_pixbuf_at_size (device, thumb, -1, -1);
pixbufs = g_list_append (pixbufs, pixbuf);
break;
case ITDB_THUMB_TYPE_INVALID:
g_assert_not_reached ();
}
return pixbufs;
}
#else
gpointer itdb_thumb_to_pixbuf_at_size (Itdb_Device *device, Itdb_Thumb *thumb,
gint width, gint height)
{
return NULL;
}
GList *itdb_thumb_to_pixbufs (Itdb_Device *device, Itdb_Thumb *thumb)
{
return NULL;
}
#endif