plug-ins: Handle single-channel OpenEXR with unknown channel names

OpenEXR allows for arbitrary channel names. Instead of failing once the common ones are checked, this patch 
checks the number of channels in the file.
If there is only one channel, it is treated as 
grayscale (similar to OpenImageIO's behavior).
A debug warning with the channel name is also printed.
This commit is contained in:
Alx Sa 2023-08-09 18:48:12 +00:00
parent 4465db5223
commit b459ce95bb
3 changed files with 93 additions and 5 deletions

View File

@ -62,6 +62,8 @@ static GimpImage * load_image (GFile *file,
gboolean interactive,
GError **error);
static void sanitize_comment (gchar *comment);
void load_dialog (void);
G_DEFINE_TYPE (Exr, exr, GIMP_TYPE_PLUG_IN)
@ -236,6 +238,7 @@ load_image (GFile *file,
layer_type = has_alpha ? GIMP_RGBA_IMAGE : GIMP_RGB_IMAGE;
break;
case IMAGE_TYPE_GRAY:
case IMAGE_TYPE_UNKNOWN_1_CHANNEL:
image_type = GIMP_GRAY;
layer_type = has_alpha ? GIMP_GRAYA_IMAGE : GIMP_GRAY_IMAGE;
break;
@ -257,6 +260,10 @@ load_image (GFile *file,
goto out;
}
if (exr_loader_get_image_type (loader) == IMAGE_TYPE_UNKNOWN_1_CHANNEL &&
interactive)
load_dialog ();
/* try to load an icc profile, it will be generated on the fly if
* chromaticities are given
*/
@ -395,3 +402,50 @@ sanitize_comment (gchar *comment)
}
}
}
void
load_dialog (void)
{
GtkWidget *dialog;
GtkWidget *label;
GtkWidget *vbox;
gchar *label_text;
gimp_ui_init (PLUG_IN_BINARY);
dialog = gimp_dialog_new (_("Import OpenEXR"),
"openexr-notice",
NULL, 0, NULL, NULL,
_("_OK"), GTK_RESPONSE_OK,
NULL);
gimp_window_set_transient (GTK_WINDOW (dialog));
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
vbox, TRUE, TRUE, 0);
gtk_widget_show (vbox);
label_text = g_strdup_printf ("<b>%s</b>\n%s", _("Unknown Channel Name"),
_("The image contains a single unknown channel.\n"
"It has been converted to grayscale."));
label = gtk_label_new (NULL);
gtk_label_set_markup (GTK_LABEL (label), label_text);
gtk_label_set_selectable (GTK_LABEL (label), TRUE);
gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
gtk_label_set_yalign (GTK_LABEL (label), 0.0);
gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
gtk_widget_show (label);
g_free (label_text);
gtk_widget_show (dialog);
/* run the dialog */
gimp_dialog_run (GIMP_DIALOG (dialog));
gtk_widget_destroy (dialog);
}

View File

@ -119,7 +119,35 @@ struct _EXRLoader
}
else
{
throw;
int channel_count = 0;
const char *channel_name = NULL;
for (ChannelList::ConstIterator i = channels_.begin();
i != channels_.end(); ++i)
{
channel_count++;
pt_ = i.channel().type;
channel_name = i.name();
}
/* Assume single channel images are grayscale,
* no matter what the channel name is. */
if (channel_count == 1)
{
format_string_ = channel_name;
image_type_ = IMAGE_TYPE_UNKNOWN_1_CHANNEL;
unknown_channel_name_ = channel_name;
/* TODO: Pass this information back so it can be displayed
* in the UI. */
printf ("OpenEXR Warning: Single channel image with unknown "
"channel %s, loading as grayscale\n", channel_name);
}
else
{
throw;
}
}
if (channels_.findChannel("A"))
@ -149,9 +177,9 @@ struct _EXRLoader
}
}
int readPixelRow(char* pixels,
int bpp,
int row)
int readPixelRow(char *pixels,
int bpp,
int row)
{
const int actual_row = data_window_.min.y + row;
FrameBuffer fb;
@ -162,6 +190,10 @@ struct _EXRLoader
switch (image_type_)
{
case IMAGE_TYPE_UNKNOWN_1_CHANNEL:
fb.insert(unknown_channel_name_, Slice(pt_, base, bpp, 0, 1, 1, 0.5));
break;
case IMAGE_TYPE_GRAY:
fb.insert("Y", Slice(pt_, base, bpp, 0, 1, 1, 0.5));
if (hasAlpha())
@ -383,6 +415,7 @@ struct _EXRLoader
EXRImageType image_type_;
bool has_alpha_;
std::string format_string_;
std::string unknown_channel_name_;
};
EXRLoader*

View File

@ -35,7 +35,8 @@ typedef enum
typedef enum
{
IMAGE_TYPE_RGB,
IMAGE_TYPE_GRAY
IMAGE_TYPE_GRAY,
IMAGE_TYPE_UNKNOWN_1_CHANNEL
} EXRImageType;