/* 3D MPO loader for Gimp - Version 0.1 * * This plug-in is based on mposplit.c * A small tool for splitting MPO files into their JPG components. * $Id: mposplit.c,v 1.5 2012/06/24 01:16:33 chris Exp $ * Copyright (C) 2009-2012, Christian Steinruecken. All rights reserved. * * This code is released under the Revised BSD Licence. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - The names of the author(s) and contributors may not be used to * endorse or promote products derived from this software without * specific prior written permission. * * DISCLAIMER: * This software is provided by the copyright holders and contributors * "as is" and any express or implied warranties, including, but not * limited to, the implied warranties of merchantability and fitness for * a particular purpose are disclaimed. In no event shall the copyright * holders be liable for any direct, indirect, incidental, special, * exemplary, or consequential damages (including, but not limited to, * procurement of substitute goods or services; loss of use, data, or * profits; or business interruption) however caused and on any theory of * liability, whether in contract, strict liability, or tort (including * negligence or otherwise) arising in any way out of the use of this * software, even if advised of the possibility of such damage. * * * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #ifdef G_OS_WIN32 #include #endif #include "libgimp/gimp.h" #include "libgimp/gimpui.h" #define LOAD_PROC "file-mpo-load" #define SAVE_PROC "file-mpo-save" #define PLUG_IN_BINARY "file-mpo" #define PLUG_IN_ROLE "gimp-file-mpo" static void query (void); static void run (const gchar *name, gint nparams, const GimpParam *param, gint *nreturn_vals, GimpParam **return_vals); static gboolean load_image (const gchar *filename, GError **error); static gboolean split_mpo (const gchar *filename); static void delete_layers (void); static gint num_images = 0; /* Number of images in MPO file */ static gchar **image_name; static FILE *fp; static gint32 image_id; static gint32 layer_id[8]; /* Number of images in MPO cannot exceed 8*/ const GimpPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run, /* run_proc */ }; MAIN() static void query (void) { static const GimpParamDef load_args[] = { { GIMP_PDB_INT32, "run-mode", "The run mode { RUN-NONINTERACTIVE (1) }" }, { GIMP_PDB_STRING, "filename", "The name of the file to load" }, { GIMP_PDB_STRING, "raw-filename", "The name entered" } }; static const GimpParamDef load_return_vals[] = { { GIMP_PDB_IMAGE, "image", "Output image" } }; gimp_install_procedure (LOAD_PROC, "Load MPO files", "No help till now", "Sashi Kumar ", "Sashi Kumar ", "24th April 2013", "3D MPO Data", NULL, GIMP_PLUGIN, G_N_ELEMENTS (load_args), G_N_ELEMENTS (load_return_vals), load_args, load_return_vals); gimp_register_load_handler (LOAD_PROC, "mpo", ""); } static void run (const gchar *name, gint nparams, const GimpParam *param, gint *nreturn_vals, GimpParam **return_vals) { static GimpParam values[2]; GimpRunMode run_mode; GimpPDBStatusType status = GIMP_PDB_SUCCESS; GError *error = NULL; run_mode = param[0].data.d_int32; *nreturn_vals = 1; *return_vals = values; values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR; if (strcmp (name, LOAD_PROC) == 0) { if (load_image (param[1].data.d_string, &error)) { *nreturn_vals = 2; values[1].type = GIMP_PDB_IMAGE; values[1].data.d_image = image_id; } else { status = GIMP_PDB_EXECUTION_ERROR; } } else { status = GIMP_PDB_CALLING_ERROR; } if (status != GIMP_PDB_SUCCESS && error) { *nreturn_vals = 2; values[1].type = GIMP_PDB_STRING; values[1].data.d_string = error->message; } values[0].data.d_status = status; } static gboolean load_image (const gchar *filename, GError **error) { gint32 size; gint i; GdkPixbuf* pixbuf; gboolean status; fp = g_fopen (filename, "rb"); if (!fp) { g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno), "Could not open '%s' for reading: %s", gimp_filename_to_utf8 (filename), g_strerror (errno)); return FALSE; } if (split_mpo (filename)) { for (i = num_images - 1; i >= 0; i--) { GError *gerror = NULL; gchar *layer_name = g_new0 (gchar, 100); /* Bad Assumption */ sprintf (layer_name, "image#%d", i+1); pixbuf = gdk_pixbuf_new_from_file(image_name[i], &gerror); remove (image_name[i]); /* FIXME: Make IO operations more efficient, blind delete is dangerous */ if (pixbuf) { if (i == num_images - 1) { image_id = gimp_image_new (gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf), GIMP_RGB); gimp_image_set_filename (image_id, filename); } layer_id[i] = gimp_layer_new_from_pixbuf (image_id, layer_name, pixbuf, 100., GIMP_NORMAL_MODE, 0, 0); gimp_image_insert_layer (image_id, layer_id[i], -1, -1); status = TRUE; g_object_unref (pixbuf); } else { g_printf ("\nError message: %s\n", gerror->message); exit (1); } free (layer_name); free (image_name[i]); } gimp_image_resize_to_layers (image_id); /* Resize the image to the maximum layer size */ if (num_images > 2) delete_layers(); } else status = FALSE; return status; } /* mposplit - Split MPO file into their JPG components. */ static gboolean split_mpo (const gchar *filename) { size_t length; /* Total length of file */ size_t amount; /* Amount read */ gint i = 0; gchar* buffer; gchar* fnmbase; gchar* ext; gchar *temp; fnmbase = strdup(filename); ext = strstr(fnmbase,".MPO"); if (ext != NULL) ext[0] = '\0'; ext = strstr(fnmbase,".mpo"); if (ext != NULL) ext[0] = '\0'; /* Obtain file size: */ fseek(fp, 0, SEEK_END); length = ftell(fp); rewind(fp); /* Allocate memory to contain the whole file: */ buffer = g_new0 (gchar ,length); amount = fread(buffer,1,length,fp); if (amount != length) return FALSE; fclose(fp); /* Now find the individual images */ gchar* view = buffer; gchar* last = NULL; image_name = g_new (gchar *, 128); /* Assuming a maximum of 128 layers */ while (view < buffer+length-4) { if (((char) view[0] % 255) == (char) 0xff) { if (((char) view[1] % 255) == (char) 0xd8) { if (((char) view[2] % 255) == (char) 0xff) { if (((char) view[3] % 255) == (char) 0xe1)/* FIXME: Make generalized check for JFIF tag 0xff 0xe0 */ { num_images++; if (last != NULL) { /* copy out the previous view */ image_name[i] = malloc (sizeof(gchar) * 200); /* Bad Assumption */ sprintf(image_name[i], "%s.image#%d", fnmbase, num_images-1); FILE* w = fopen(image_name[i], "wb"); fwrite(last, 1, view-last, w); fclose(w); i++; } last = view; view+=4; } else view+=2; } else view+=3; } else view+=1; } else view+=1; } if (num_images > 1) { image_name[i] = malloc (sizeof(gchar) * 200);; sprintf(image_name[i], "%s.image#%d", fnmbase, num_images); FILE* w = fopen(image_name[i], "wb"); fwrite(last, 1, buffer+length-last, w); fclose(w); } g_free(buffer); return TRUE; } /* delete_layers() * The MPO file has only two views. But the file may contain duplicate images. * Hence they must be removed from the buffer to reduce the memory occupied by the file */ static void delete_layers (void) { gint width, height; gint i; width = gimp_image_width(image_id); height = gimp_image_height(image_id); for (i = 0; i < num_images; i++) { if ((gimp_drawable_width (layer_id[i]) < width) && (gimp_drawable_height(layer_id[i]) < height)) gimp_image_remove_layer (image_id, layer_id[i]); else gimp_drawable_set_name ( } }