static void
append_basic_info (NemoImagePropertiesPage *page)
{
	GdkPixbufFormat *format;
	char *name;
	char *desc;
	char *value;

	format = gdk_pixbuf_loader_get_format (page->details->loader);

	name = gdk_pixbuf_format_get_name (format);
	desc = gdk_pixbuf_format_get_description (format);
	value = g_strdup_printf ("%s (%s)", name, desc);
	g_free (name);
	g_free (desc);
	append_item (page, _("Image Type"), value);
	g_free (value);
	value = g_strdup_printf (ngettext ("%d pixel",
					   "%d pixels",
					   page->details->width),
				 page->details->width);
	append_item (page, _("Width"), value);
	g_free (value);
	value = g_strdup_printf (ngettext ("%d pixel",
					   "%d pixels",
					   page->details->height),
				 page->details->height);
	append_item (page, _("Height"), value);
	g_free (value);
}
Exemple #2
0
void           
file_chooser_dialog_add_writable_pixbuf_formats (GtkFileChooser *chooser)
{
	GSList *pixbuf_formats = NULL;
	GSList *iter;
	GtkFileFilter *filter;
	int i;
  
	filter = gtk_file_filter_new();
	gtk_file_filter_set_name (filter, _("By extension"));
	g_object_set_data (G_OBJECT(filter), "pixbuf-format", NULL);
	gtk_file_chooser_add_filter (chooser, filter);

	pixbuf_formats = gdk_pixbuf_get_formats ();

	for (iter = pixbuf_formats; iter; iter = iter->next) {
		GdkPixbufFormat *format = iter->data;

	        gchar *description, *name, *extensions;
		gchar **extension_list, **mime_types;

		if (gdk_pixbuf_format_is_disabled (format) ||
	    	    !gdk_pixbuf_format_is_writable (format))
		            continue;

	        name = gdk_pixbuf_format_get_description (format);
	        extension_list = gdk_pixbuf_format_get_extensions (format);
	        extensions = g_strjoinv (", ", extension_list);
		g_strfreev (extension_list);
		description = g_strdup_printf ("%s (%s)", name, extensions);

		filter = gtk_file_filter_new ();
		gtk_file_filter_set_name (filter, description);
		g_object_set_data (G_OBJECT (filter), "pixbuf-format", format);
		gtk_file_chooser_add_filter (chooser, filter);

		g_free (description);
		g_free (extensions);
		g_free (name);

		mime_types = gdk_pixbuf_format_get_mime_types (format);
		for (i = 0; mime_types[i] != 0; i++)
			gtk_file_filter_add_mime_type (filter, mime_types[i]);
		g_strfreev (mime_types);
	}

	g_slist_free (pixbuf_formats);
}
static void
go_image_build_pixbuf_format_infos (void)
{
#ifdef GOFFICE_WITH_GTK
	GdkPixbufFormat *fmt;
	GSList *l, *pixbuf_fmts;
	GOImageFormatInfo *format_info;
	gchar **exts;
	unsigned i;

	if (pixbuf_format_done)
		return;

	pixbuf_fmts = gdk_pixbuf_get_formats ();
	pixbuf_format_nbr = g_slist_length (pixbuf_fmts);

	if (pixbuf_format_nbr > 0) {
		pixbuf_image_format_infos = g_new (GOImageFormatInfo, pixbuf_format_nbr);

		for (l = pixbuf_fmts, i = 1, format_info = pixbuf_image_format_infos;
		     l != NULL;
		     l = l->next, i++, format_info++) {
			fmt = (GdkPixbufFormat *)l->data;

			format_info->format = GO_IMAGE_FORMAT_UNKNOWN + i;
			format_info->name = gdk_pixbuf_format_get_name (fmt);
			format_info->desc = gdk_pixbuf_format_get_description (fmt);
			exts = gdk_pixbuf_format_get_extensions (fmt);
			format_info->ext = g_strdup (exts[0]);
			if (format_info->ext == NULL)
				format_info->ext = format_info->name;
			g_strfreev (exts);
			format_info->has_pixbuf_saver = gdk_pixbuf_format_is_writable (fmt);
			format_info->is_dpi_useful = FALSE;
			format_info->alpha_support = FALSE;
		}
	}

	g_slist_free (pixbuf_fmts);
#endif /* GOFFICE_WITH_GTK */
	pixbuf_format_done = TRUE;
}
Exemple #4
0
static void
sanity_check(const gchar *filename)
{
    GdkPixbufLoader *loader;
    GSList *formats, *l;
    GError *err = NULL;
    GdkPixbuf *pixbuf;
    gchar *buf = NULL;
    gsize size;
    FILE *fh;
    gboolean ok, fileok = TRUE;

    g_printerr("Performing sanity check for %s.\n", filename);
    fileok &= ok = g_file_test(filename, G_FILE_TEST_EXISTS);
    g_printerr("Does it exist: %s\n", ok ? "YES" : "NO");
    fileok &= ok = g_file_test(filename, G_FILE_TEST_IS_REGULAR);
    g_printerr("Is it a regular file: %s\n", ok ? "YES" : "NO");

    fh = fopen(filename, "rb");
    fileok &= ok = !!fh;
    g_printerr("Can we open it for reading: %s\n", ok ? "YES" : "NO");
    if (fh)
        fclose(fh);
    else
        g_printerr("fopen() fails with: %s\n", g_strerror(errno));

    fileok &= ok = g_file_get_contents(filename, &buf, &size, &err);
    g_printerr("Can we use g_file_get_contents(): %s\n", ok ? "YES" : "NO");
    if (!ok) {
        g_printerr("g_file_get_contents() fails with: %s\n", err->message);
        g_clear_error(&err);
    }

    if (!fileok) {
        if (buf)
            g_free(buf);
        g_printerr("The file does not seem OK.  No point continuing.\n");
        return;
    }
    g_printerr("The file seems OK, continuing checks.\n");

    pixbuf = gdk_pixbuf_new_from_file(filename, &err);
    if (pixbuf) {
        g_printerr("Apparently we can load the pixbuf (%dx%d) now?!\n",
                   gdk_pixbuf_get_width(pixbuf),
                   gdk_pixbuf_get_height(pixbuf));
        g_printerr("What has changed?\n");
        g_printerr("This is completely f****d up.\n");
        g_object_unref(pixbuf);
    }
    else {
        g_printerr("gdk_pixbuf_new_from_file() fails with: %s\n", err->message);
        g_clear_error(&err);
    }

    g_printerr("Checking the pixbuf loaders.\n");

    formats = gdk_pixbuf_get_formats();
    for (l = formats; l; l = g_slist_next(l)) {
        GdkPixbufFormat *pixbuf_format = (GdkPixbufFormat*)l->data;
        gchar **ext;
        gchar *fmtname, *desc, *exts;

        fmtname = gdk_pixbuf_format_get_name(pixbuf_format);
        desc = gdk_pixbuf_format_get_description(pixbuf_format);
        ext = gdk_pixbuf_format_get_extensions(pixbuf_format);
        exts = g_strjoinv(" ", ext);
        g_printerr("Found format %s: %s (%s)\n", fmtname, desc, exts);
        g_free(exts);
        g_strfreev(ext);
        g_free(desc);

        format_check(pixbuf_format, buf, size);

        loader = gdk_pixbuf_loader_new_with_type(fmtname, &err);
        if (!loader) {
            g_printerr("  Cannot create loader for %s: %s\n",
                       fmtname, err->message);
            g_clear_error(&err);
            g_free(fmtname);
            continue;
        }

        ok = gdk_pixbuf_loader_write(loader, buf, size, &err);
        if (ok) {
            g_printerr("  Loader %s accepts the file content.\n", fmtname);
            ok = gdk_pixbuf_loader_close(loader, &err);
            if (ok) {
                g_printerr("  Loader %s accepts the entire file.\n", fmtname);
                pixbuf = gdk_pixbuf_loader_get_pixbuf(loader);
                if (pixbuf) {
                    g_printerr("  Obtained pixbuf %dx%d from the loader.\n",
                               gdk_pixbuf_get_width(pixbuf),
                               gdk_pixbuf_get_height(pixbuf));
                }
                else {
                    g_printerr("  Cannot obtain pixbuf from the loader.\n");
                }
            }
            else {
                g_printerr("  Loader %s fails at close(): %s.\n",
                           fmtname, err->message);
                g_clear_error(&err);
            }
        }
        else {
            g_printerr("  Loader %s does not accept the file content: %s\n",
                       fmtname, err->message);
            g_clear_error(&err);
        }
        g_object_unref(loader);

        g_free(fmtname);
    }

    g_slist_free(formats);
}
static void
load_finished (CajaImagePropertiesPage *page)
{
    GdkPixbufFormat *format;
    char *name, *desc;

    gtk_widget_destroy (page->details->loading_label);

    if (page->details->loader != NULL) {
        gdk_pixbuf_loader_close (page->details->loader, NULL);
    }

    if (page->details->got_size)
    {
#ifdef HAVE_EXIF
        ExifData *exif_data;
#endif /*HAVE_EXIF*/

        format = gdk_pixbuf_loader_get_format (page->details->loader);

        name = gdk_pixbuf_format_get_name (format);
        desc = gdk_pixbuf_format_get_description (format);
        append_label_take_str
        (page->details->vbox,
         g_strdup_printf ("<b>%s</b> %s (%s)",
                          _("Image Type:"), name, desc));
        append_label_take_str
        (page->details->vbox,
         g_strdup_printf (ngettext ("<b>Width:</b> %d pixel",
                                    "<b>Width:</b> %d pixels",
                                    page->details->width),
                          page->details->width));
        append_label_take_str
        (page->details->vbox,
         g_strdup_printf (ngettext ("<b>Height:</b> %d pixel",
                                    "<b>Height:</b> %d pixels",
                                    page->details->height),
                          page->details->height));
        g_free (name);
        g_free (desc);

#ifdef HAVE_EXIF
        exif_data = exif_loader_get_data (page->details->exifldr);
        append_exifdata_string (exif_data, page);
        exif_data_unref (exif_data);
#endif /*HAVE_EXIF*/
#ifdef HAVE_EXEMPI
        append_xmpdata_string (page->details->xmp, page);
#endif /*HAVE_EXEMPI*/
    }
    else
    {
        append_label (page->details->vbox,
                      _("Failed to load image information"));
    }

    if (page->details->loader != NULL)
    {
        g_object_unref (page->details->loader);
        page->details->loader = NULL;
    }
#ifdef HAVE_EXIF
    if (page->details->exifldr != NULL)
    {
        exif_loader_unref (page->details->exifldr);
        page->details->exifldr = NULL;
    }
#endif /*HAVE_EXIF*/
#ifdef HAVE_EXEMPI
    if (page->details->xmp != NULL)
    {
        xmp_free(page->details->xmp);
        page->details->xmp = NULL;
    }
#endif /*HAVE_EXEMPI*/
}
void
GdkpixbufInput::init(void)
{
    GSList * formatlist, * formatlisthead;

    /* \todo I'm not sure if I need to free this list */
    for (formatlist = formatlisthead = gdk_pixbuf_get_formats();
            formatlist != NULL;
            formatlist = g_slist_next(formatlist)) {

        GdkPixbufFormat *pixformat = (GdkPixbufFormat *)formatlist->data;

        gchar *name =        gdk_pixbuf_format_get_name(pixformat);
        gchar *description = gdk_pixbuf_format_get_description(pixformat);
        gchar **extensions =  gdk_pixbuf_format_get_extensions(pixformat);
        gchar **mimetypes =   gdk_pixbuf_format_get_mime_types(pixformat);

        for (int i = 0; extensions[i] != NULL; i++) {
            for (int j = 0; mimetypes[j] != NULL; j++) {

                /* thanks but no thanks, we'll handle SVG extensions... */
                if (strcmp(extensions[i], "svg") == 0) {
                    continue;
                }
                if (strcmp(extensions[i], "svgz") == 0) {
                    continue;
                }
                if (strcmp(extensions[i], "svg.gz") == 0) {
                    continue;
                }
                gchar *caption = g_strdup_printf(_("%s bitmap image import"), name);

                gchar *xmlString = g_strdup_printf(
                                       "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
                                       "<name>%s</name>\n"
                                       "<id>org.inkscape.input.gdkpixbuf.%s</id>\n"

                                       "<param name='link' type='optiongroup' appearance='full' _gui-text='" N_("Image Import Type:") "' _gui-description='" N_("Embed results in stand-alone, larger SVG files. Link references a file outside this SVG document and all files must be moved together.") "' >\n"
                                       "<_option value='embed' >" N_("Embed") "</_option>\n"
                                       "<_option value='link' >" N_("Link") "</_option>\n"
                                       "</param>\n"

                                       "<param name='dpi' type='optiongroup' appearance='full' _gui-text='" N_("Image DPI:") "' _gui-description='" N_("Take information from file or use default bitmap import resolution as defined in the preferences.") "' >\n"
                                       "<_option value='from_file' >" N_("From file") "</_option>\n"
                                       "<_option value='from_default' >" N_("Default import resolution") "</_option>\n"
                                       "</param>\n"

                                       "<param name='scale' type='optiongroup' appearance='full' _gui-text='" N_("Image Rendering Mode:") "' _gui-description='" N_("When an image is upscaled, apply smoothing or keep blocky (pixelated). (Will not work in all browsers.)") "' >\n"
                                       "<_option value='auto' >" N_("None (auto)") "</_option>\n"
                                       "<_option value='optimizeQuality' >" N_("Smooth (optimizeQuality)") "</_option>\n"
                                       "<_option value='optimizeSpeed' >" N_("Blocky (optimizeSpeed)") "</_option>\n"
                                       "</param>\n"

                                       "<param name=\"do_not_ask\" _gui-description='" N_("Hide the dialog next time and always apply the same actions.") "' gui-text=\"" N_("Don't ask again") "\" type=\"boolean\" >false</param>\n"
                                       "<input>\n"
                                       "<extension>.%s</extension>\n"
                                       "<mimetype>%s</mimetype>\n"
                                       "<filetypename>%s (*.%s)</filetypename>\n"
                                       "<filetypetooltip>%s</filetypetooltip>\n"
                                       "</input>\n"
                                       "</inkscape-extension>",
                                       caption,
                                       extensions[i],
                                       extensions[i],
                                       mimetypes[j],
                                       name,
                                       extensions[i],
                                       description
                                   );

                Inkscape::Extension::build_from_mem(xmlString, new GdkpixbufInput());
                g_free(xmlString);
                g_free(caption);
            }
        }

        g_free(name);
        g_free(description);
        g_strfreev(mimetypes);
        g_strfreev(extensions);
    }

    g_slist_free(formatlisthead);
}
Exemple #7
0
void filter_add_defaults(void)
{
	GSList *list, *work;

	list = gdk_pixbuf_get_formats();
	work = list;
	while (work)
		{
		GdkPixbufFormat *format;
		gchar *name;
		gchar *desc;
		gchar **extensions;
		GString *filter = NULL;
		gint i;
		
		format = work->data;
		work = work->next;

		name = gdk_pixbuf_format_get_name(format);
		desc = gdk_pixbuf_format_get_description(format);
		extensions = gdk_pixbuf_format_get_extensions(format);

		i = 0;
		while (extensions[i])
			{
			if (!filter)
				{
				filter = g_string_new(".");
				filter = g_string_append(filter, extensions[i]);
				}
			else
				{
				filter = g_string_append(filter, ";.");
				filter = g_string_append(filter, extensions[i]);
				}
			i++;
			}

		if (debug) printf("loader reported [%s] [%s] [%s]\n", name, desc, filter->str);

		filter_add_if_missing(name, desc, filter->str, TRUE);

		g_free(name);
		g_free(desc);
		g_strfreev(extensions);
		g_string_free(filter, TRUE);
		}
	g_slist_free(list);

	/* add defaults even if gdk-pixbuf does not have them, but disabled */
	filter_add_if_missing("jpeg", "JPEG group", ".jpg;.jpeg;.jpe", FALSE);
	filter_add_if_missing("png", "Portable Network Graphic", ".png", FALSE);
	filter_add_if_missing("tiff", "Tiff", ".tif;.tiff", FALSE);
	filter_add_if_missing("pnm", "Packed Pixel formats", ".pbm;.pgm;.pnm;.ppm", FALSE);
	filter_add_if_missing("gif", "Graphics Interchange Format", ".gif", FALSE);
	filter_add_if_missing("xbm", "X bitmap", ".xbm", FALSE);
	filter_add_if_missing("xpm", "X pixmap", ".xpm", FALSE);
	filter_add_if_missing("bmp", "Bitmap", ".bmp", FALSE);
	filter_add_if_missing("ico", "Icon file", ".ico;.cur", FALSE);
	filter_add_if_missing("ras", "Raster", ".ras", FALSE);
	filter_add_if_missing("svg", "Scalable Vector Graphics", ".svg", FALSE);

	/* These are the raw camera formats with embedded jpeg/exif.
	 * (see format_raw.c)
	 */
	filter_add_if_missing("crw", "Canon raw format", ".crw;.cr2", TRUE);
	filter_add_if_missing("raf", "Fujifilm raw format", ".raf", TRUE);
	filter_add_if_missing("nef", "Nikon raw format", ".nef", TRUE);
	filter_add_if_missing("orf", "Olympus raw format", ".orf", TRUE);
	filter_add_if_missing("pef", "Pentax raw format", ".pef", TRUE);
}
static VALUE
rg_description(VALUE self)
{
    return CSTR2RVAL_FREE(gdk_pixbuf_format_get_description(_SELF(self)));
}
static void
gth_metadata_provider_image_read (GthMetadataProvider *self,
				  GthFileData         *file_data,
				  const char          *attributes,
				  GCancellable        *cancellable)
{
	gboolean          format_recognized;
	GFileInputStream *stream;
	char             *description = NULL;
	int               width;
	int               height;
	const char       *mime_type = NULL;

	format_recognized = FALSE;

	stream = g_file_read (file_data->file, cancellable, NULL);
	if (stream != NULL) {
		int     buffer_size;
		guchar *buffer;
		gssize  size;

		buffer_size = BUFFER_SIZE;
		buffer = g_new (guchar, buffer_size);
		size = g_input_stream_read (G_INPUT_STREAM (stream),
					    buffer,
					    buffer_size,
					    cancellable,
					    NULL);
		if (size >= 0) {
			if ((size >= 24)

			    /* PNG signature */

			    && (buffer[0] == 0x89)
			    && (buffer[1] == 0x50)
			    && (buffer[2] == 0x4E)
			    && (buffer[3] == 0x47)
			    && (buffer[4] == 0x0D)
			    && (buffer[5] == 0x0A)
			    && (buffer[6] == 0x1A)
			    && (buffer[7] == 0x0A)

			    /* IHDR Image header */

			    && (buffer[12] == 0x49)
    			    && (buffer[13] == 0x48)
    			    && (buffer[14] == 0x44)
    			    && (buffer[15] == 0x52))
			{
				/* PNG */

				width  = (buffer[16] << 24) + (buffer[17] << 16) + (buffer[18] << 8) + buffer[19];
				height = (buffer[20] << 24) + (buffer[21] << 16) + (buffer[22] << 8) + buffer[23];
				description = _("PNG");
				mime_type = "image/png";
				format_recognized = TRUE;
			}

#if HAVE_LIBJPEG
			else if ((size >= 4)
				 && (buffer[0] == 0xff)
				 && (buffer[1] == 0xd8)
				 && (buffer[2] == 0xff))
			{
				/* JPEG */

				GthTransform orientation;

				if (g_seekable_can_seek (G_SEEKABLE (stream))) {
					g_seekable_seek (G_SEEKABLE (stream), 0, G_SEEK_SET, cancellable, NULL);
				}
				else {
					g_object_unref (stream);
					stream = g_file_read (file_data->file, cancellable, NULL);
				}

				if (_jpeg_get_image_info (G_INPUT_STREAM (stream),
							  &width,
							  &height,
							  &orientation,
							  cancellable,
							  NULL))
				{
					description = _("JPEG");
					mime_type = "image/jpeg";
					format_recognized = TRUE;

					if ((orientation == GTH_TRANSFORM_ROTATE_90)
					     ||	(orientation == GTH_TRANSFORM_ROTATE_270)
					     ||	(orientation == GTH_TRANSFORM_TRANSPOSE)
					     ||	(orientation == GTH_TRANSFORM_TRANSVERSE))
					{
						int tmp = width;
						width = height;
						height = tmp;
					}
				}
			}
#endif /* HAVE_LIBJPEG */

#if HAVE_LIBWEBP
			else if ((size > 15) && (memcmp (buffer + 8, "WEBPVP8", 7) == 0)) {
				WebPDecoderConfig config;

				if (WebPInitDecoderConfig (&config)) {
					if (WebPGetFeatures (buffer, buffer_size, &config.input) == VP8_STATUS_OK) {
						width = config.input.width;
						height = config.input.height;
						description = _("WebP");
						mime_type = "image/webp";
						format_recognized = TRUE;
					}
					WebPFreeDecBuffer (&config.output);
				}
			}
#endif /* HAVE_LIBWEBP */

			else if ((size >= 26)
				 && (strncmp ((char *) buffer, "gimp xcf ", 9) == 0))
			{
				/* XCF */

				GInputStream      *mem_stream;
				GDataInputStream  *data_stream;

				mem_stream = g_memory_input_stream_new_from_data (buffer, BUFFER_SIZE, NULL);
				data_stream = g_data_input_stream_new (mem_stream);
				g_data_input_stream_set_byte_order (data_stream, G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN);

				if (g_seekable_seek (G_SEEKABLE (data_stream), 14, G_SEEK_SET, NULL, NULL)) {
					int base_type;

					width  = g_data_input_stream_read_uint32 (data_stream, NULL, NULL);
					height = g_data_input_stream_read_uint32 (data_stream, NULL, NULL);
					base_type = g_data_input_stream_read_uint32 (data_stream, NULL, NULL);
					if (base_type == 0)
						description = "XCF RGB";
					else if (base_type == 1)
						description = "XCF grayscale";
					else if (base_type == 2)
						description = "XCF indexed";
					else
						description = "XCF";
					mime_type = "image/x-xcf";
					format_recognized = TRUE;
				}

				g_object_unref (data_stream);
				g_object_unref (mem_stream);
			}
		}

		g_free (buffer);
		g_object_unref (stream);
	}

	if (! format_recognized) { /* use gdk_pixbuf_get_file_info */
		char *filename;

		filename = g_file_get_path (file_data->file);
		if (filename != NULL) {
			GdkPixbufFormat  *format;

			format = gdk_pixbuf_get_file_info (filename, &width, &height);
			if (format != NULL) {
				format_recognized = TRUE;
				description = gdk_pixbuf_format_get_description (format);
			}

			g_free (filename);
		}
	}

	if (format_recognized) {
		char *size;

		g_file_info_set_attribute_string (file_data->info, "general::format", description);

		g_file_info_set_attribute_int32 (file_data->info, "image::width", width);
		g_file_info_set_attribute_int32 (file_data->info, "image::height", height);
		g_file_info_set_attribute_int32 (file_data->info, "frame::width", width);
		g_file_info_set_attribute_int32 (file_data->info, "frame::height", height);

		if (mime_type != NULL)
			gth_file_data_set_mime_type (file_data, mime_type);

		size = g_strdup_printf (_("%d × %d"), width, height);
		g_file_info_set_attribute_string (file_data->info, "general::dimensions", size);

		g_free (size);
	}
}
Exemple #10
0
char* get_save_filename( GtkWindow* parent, const char* cwd, char** type )
{
    char* file = NULL;
    GtkFileChooser* dlg = (GtkFileChooser*)gtk_file_chooser_dialog_new( NULL, parent,
            GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL,
            GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_OK, NULL );
    GSList* modules, *module;
    GtkFileFilter *filter;

    gtk_file_chooser_set_current_folder( dlg, cwd );

    GtkWidget* img = gtk_image_new();
    gtk_widget_set_size_request( img, 128, 128 );
    gtk_file_chooser_set_preview_widget( dlg, img );
    g_signal_connect( dlg, "update-preview", G_CALLBACK(on_update_preview), img );
    g_signal_connect( dlg, "notify::filter", G_CALLBACK(on_file_save_filter_changed), NULL );

    /*
    /// TODO: determine file type from file name
    filter = gtk_file_filter_new();
    gtk_file_filter_set_name( filter, _("Determined by File Name") );
    gtk_file_filter_add_pixbuf_formats( filter );
    gtk_file_chooser_add_filter( dlg, filter );
    */

    modules = gdk_pixbuf_get_formats();
    for( module = modules; module; module = module->next )
    {
        char *name, *desc, *tmp;
        char **exts, **mimes, **mime;

        GdkPixbufFormat* format = (GdkPixbufFormat*)module->data;
        if( ! gdk_pixbuf_format_is_writable( format ) )
            continue;

        filter = gtk_file_filter_new();

        name = gdk_pixbuf_format_get_name( format );
        desc = gdk_pixbuf_format_get_description( format );
        exts = gdk_pixbuf_format_get_extensions( format );
        mimes = gdk_pixbuf_format_get_mime_types( format );
        tmp = g_strdup_printf( "%s (*.%s)", desc, exts[0], NULL );

        g_object_set_data_full(G_OBJECT(filter), "type", name, (GDestroyNotify)g_free);
        g_strfreev(exts);
        g_free( desc );
        gtk_file_filter_set_name( filter, tmp );
        g_free( tmp );

        for( mime  = mimes; *mime ; ++mime )
            gtk_file_filter_add_mime_type( filter, *mime );
        g_strfreev( mimes );
        gtk_file_chooser_add_filter( dlg, filter );
    }
    g_slist_free( modules );

    int initial_jpg_quality = pref.jpg_quality;
    int initial_png_compression = pref.png_compression;

    if( gtk_dialog_run( (GtkDialog*)dlg ) == GTK_RESPONSE_OK )
    {
        filter = gtk_file_chooser_get_filter( dlg );
        file = gtk_file_chooser_get_filename( dlg );
        *type = g_object_steal_data(G_OBJECT(filter), "type");

        if( !*type )   // auto detection
        {
            /// TODO: auto file type
        }
        else
        {
            /* TODO: append appropriate extension if needed. */
        }
    }
    gtk_widget_destroy( (GtkWidget*)dlg );

    if ((initial_jpg_quality != pref.jpg_quality) || (initial_png_compression != pref.png_compression))
        save_preferences();

    return file;
}
static void
append_xmp_value_pair (GString    *string,
		       XmpPtr      xmp,
		       const char *ns,
		       const char *propname,
		       char       *descr)
{
	uint32_t options;
	XmpStringPtr value;

	value = xmp_string_new();
#ifdef HAVE_EXEMPI_NEW_API
	if (xmp_get_property (xmp, ns, propname, value, &options)) {
#else
	if (xmp_get_property_and_bits (xmp, ns, propname, value, &options)) {
#endif
		if (XMP_IS_PROP_SIMPLE (options)) {
			g_string_append_printf (string,
						"<b>%s:</b> %s\n",
						descr,
						xmp_string_cstr (value));
		}
		else if (XMP_IS_PROP_ARRAY (options)) {
			XmpIteratorPtr iter;

			iter = xmp_iterator_new (xmp, ns, propname, XMP_ITER_JUSTLEAFNODES);
			if (iter) {
				gboolean first = TRUE;
				g_string_append_printf (string, "<b>%s:</b> ", descr);
				while (xmp_iterator_next (iter, NULL, NULL, value, &options) 
				       && !XMP_IS_PROP_QUALIFIER(options)) {
					if (!first) {
						g_string_append_printf (string, ", ");
					}
					else {
						first = FALSE;
					}
					g_string_append_printf (string,
								"%s",
								xmp_string_cstr(value));
				}
				xmp_iterator_free(iter);
				g_string_append_printf(string, "\n");
			}
		}
	}
	xmp_string_free(value);
}

static void
append_xmpdata_string(XmpPtr xmp, GString *string)
{
	if(xmp != NULL) {
		append_xmp_value_pair(string, xmp, NS_IPTC4XMP, "Location", _("Location"));
		append_xmp_value_pair(string, xmp, NS_DC, "description", _("Description"));
		append_xmp_value_pair(string, xmp, NS_DC, "subject", _("Keywords"));
		append_xmp_value_pair(string, xmp, NS_DC, "creator", _("Creator"));
		append_xmp_value_pair(string, xmp, NS_DC, "rights", _("Copyright"));
		append_xmp_value_pair(string, xmp, NS_XAP,"Rating", _("Rating"));
		/* TODO add CC licenses */
	}
}
#endif

static void
load_finished (NautilusImagePropertiesPage *page)
{
	GdkPixbufFormat *format;
	char *name, *desc;
	GString *str;

	if (page->details->got_size) {
#ifdef HAVE_EXIF
                ExifData *exif_data;
#endif

		str = g_string_new (NULL);
		format = gdk_pixbuf_loader_get_format (page->details->loader);
	
		name = gdk_pixbuf_format_get_name (format);
		desc = gdk_pixbuf_format_get_description (format);
		g_string_append_printf (str, "<b>%s</b> %s (%s)\n",
					_("Image Type:"), name, desc);
		g_string_append_printf (str, ngettext ("<b>Width:</b> %d pixel\n",
						       "<b>Width:</b> %d pixels\n",
						       page->details->width),
					page->details->width);
		g_string_append_printf (str, ngettext ("<b>Height:</b> %d pixel\n",
						       "<b>Height:</b> %d pixels\n",
						       page->details->height),
					page->details->height);
		g_free (name);
		g_free (desc);
		
#ifdef HAVE_EXIF
		exif_data = exif_loader_get_data (page->details->exifldr);
                append_exifdata_string (exif_data, str);
                exif_data_unref (exif_data);
#endif /*HAVE_EXIF*/
#ifdef HAVE_EXEMPI
		append_xmpdata_string(page->details->xmp, str);
#endif /*HAVE EXEMPI*/
		
		gtk_label_set_markup (GTK_LABEL (page->details->resolution), str->str);
		gtk_label_set_selectable (GTK_LABEL (page->details->resolution), TRUE);
		g_string_free (str, TRUE);
	} else {
		gtk_label_set_text (GTK_LABEL (page->details->resolution), _("Failed to load image information"));
	}

	if (page->details->loader != NULL) {
		gdk_pixbuf_loader_close (page->details->loader, NULL);
		g_object_unref (page->details->loader);
		page->details->loader = NULL;
	}
#ifdef HAVE_EXIF
	if (page->details->exifldr != NULL) {
		exif_loader_unref (page->details->exifldr);
		page->details->exifldr = NULL;
	}
#endif /*HAVE_EXIF*/
#ifdef HAVE_EXEMPI
	if (page->details->xmp != NULL) {
		xmp_free(page->details->xmp);
		page->details->xmp = NULL;
	}
#endif
}