Photoshop PSD support
authorDalai Felinto <dfelinto@gmail.com>
Tue, 8 Oct 2013 21:17:24 +0000 (21:17 +0000)
committerDalai Felinto <dfelinto@gmail.com>
Tue, 8 Oct 2013 21:17:24 +0000 (21:17 +0000)
We now support the combined layer of Photoshop files (stored as layer 0
in the file). This way users can keep their files as multilayer PSD and
Blender always handle them as flat images.

For perfect alpha this requires an OpenImageIO update:
https://github.com/OpenImageIO/oiio/commit/342cc2633ff590a3bb278481c61ae798c7148361

Photoshop sample files:
https://github.com/OpenImageIO/oiio-images

Brecht has some pending fixes to push for OIIO as well, so we may as
well wait to update our libraries.

What works:
===========
* 8bit images (with or without alpha)
* 16bits images (alpha discarded)
* Photoshop files saved with 'Maximum Compatibility'
* Cycles, Blender internal,  BGE (and player)

Known limitations
(due to OIIO dependency):
=========================
* Images with less than 4 channels show a wrong thumbnail (bug may be in  OIIO)
* Packed images are not supported
* We do not write PSD files.

Note: old Blenders have support for PSD via Quicktime library. But due
to license issues this was discontinued.

Many thanks for Brecht van Lommel for reviewing the patch, suggesting
multiple improvements and to help solving the alpha issue.

26 files changed:
CMakeLists.txt
SConstruct
source/blender/CMakeLists.txt
source/blender/blenkernel/intern/image.c
source/blender/editors/space_file/CMakeLists.txt
source/blender/editors/space_image/CMakeLists.txt
source/blender/imbuf/CMakeLists.txt
source/blender/imbuf/IMB_imbuf.h
source/blender/imbuf/IMB_imbuf_types.h
source/blender/imbuf/intern/IMB_filetype.h
source/blender/imbuf/intern/colormanagement.c
source/blender/imbuf/intern/filetype.c
source/blender/imbuf/intern/oiio/CMakeLists.txt [new file with mode: 0644]
source/blender/imbuf/intern/oiio/SConscript [new file with mode: 0644]
source/blender/imbuf/intern/oiio/openimageio_api.cpp [new file with mode: 0644]
source/blender/imbuf/intern/oiio/openimageio_api.h [new file with mode: 0644]
source/blender/imbuf/intern/oiio/openimageio_stub.cpp [new file with mode: 0644]
source/blender/imbuf/intern/readimage.c
source/blender/imbuf/intern/util.c
source/blender/imbuf/intern/writeimage.c
source/blender/makesdna/DNA_scene_types.h
source/blender/makesrna/intern/CMakeLists.txt
source/blender/makesrna/intern/rna_scene.c
source/blender/python/intern/CMakeLists.txt
source/blenderplayer/CMakeLists.txt
source/creator/CMakeLists.txt

index 8863c03bff4372b9a06edeaba41d9ac30cead3a7..e88a5e0eea7ed423bfa31c81bd7b4092300db8b8 100644 (file)
@@ -206,6 +206,7 @@ option(WITH_MOD_OCEANSIM        "Enable Ocean Modifier" OFF)
 option(WITH_IMAGE_OPENEXR       "Enable OpenEXR Support (http://www.openexr.com)" ON)
 option(WITH_IMAGE_OPENJPEG      "Enable OpenJpeg Support (http://www.openjpeg.org)" ON)
 option(WITH_IMAGE_TIFF          "Enable LibTIFF Support" ON)
+option(WITH_IMAGE_PSD           "Enable Photoshop PSD Support" ON)
 option(WITH_IMAGE_DDS           "Enable DDS Image Support" ON)
 option(WITH_IMAGE_CINEON        "Enable CINEON and DPX Image Support" ON)
 option(WITH_IMAGE_HDR           "Enable HDR Image Support" ON)
@@ -441,6 +442,11 @@ if(NOT WITH_PYTHON)
        set(WITH_CYCLES OFF)
 endif()
 
+# auto enable openimageio for photoshop psd
+if(WITH_IMAGE_PSD)
+       set(WITH_OPENIMAGEIO ON)
+endif()
+
 # enable boost for cycles, booleans, audaspace or i18n
 # otherwise if the user disabled
 if(NOT WITH_BOOST)
@@ -2297,6 +2303,7 @@ if(FIRST_RUN)
        info_cfg_option(WITH_IMAGE_OPENJPEG)
        info_cfg_option(WITH_IMAGE_REDCODE)
        info_cfg_option(WITH_IMAGE_TIFF)
+       info_cfg_option(WITH_IMAGE_PSD)
 
        info_cfg_text("Audio:")
        info_cfg_option(WITH_OPENAL)
index f95a2903db1dd3f695b65640aae54db0b70015f3..539414d6fba98173019da83884974b7ed5b9135a 100644 (file)
@@ -246,6 +246,7 @@ if 'blenderlite' in B.targets:
     target_env_defs['WITH_BF_CYCLES'] = False
     target_env_defs['WITH_BF_OPENAL'] = False
     target_env_defs['WITH_BF_OPENEXR'] = False
+    target_env_defs['WITH_BF_PSD'] = False
     target_env_defs['WITH_BF_OPENMP'] = False
     target_env_defs['WITH_BF_ICONV'] = False
     target_env_defs['WITH_BF_INTERNATIONAL'] = False
index 7e327028a01e07b110aab522efe81bc0778db1ff..307f93dd60672198ffa54f181bc704667604bfa8 100644 (file)
@@ -117,6 +117,10 @@ if(WITH_IMAGE_OPENEXR)
        add_subdirectory(imbuf/intern/openexr)
 endif()
 
+if(WITH_IMAGE_PSD)
+       add_subdirectory(imbuf/intern/oiio)
+endif()
+
 if(WITH_IMAGE_DDS)
        add_subdirectory(imbuf/intern/dds)
 endif()
index 2bf6304b04b83805226348f0b28bed048725ea48..a11d705398f2f1584da1f220c975dead09e78238 100644 (file)
@@ -1250,6 +1250,12 @@ static int do_add_image_extension(char *string, const char imtype, const ImageFo
                }
        }
 #endif
+#ifdef WITH_PSD
+       else if (imtype == R_IMF_IMTYPE_PSD) {
+               if (!BLI_testextensie(string, ".psd"))
+                       extension = ".psd";
+       }
+#endif
 #ifdef WITH_OPENEXR
        else if (ELEM(imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER)) {
                if (!BLI_testextensie(string, ".exr"))
index b30f008e1bfed39b66aa104c3bdd1a384c54cc29..74f3a425c25ed0e8338d4627e8b46c9a8297b870 100644 (file)
@@ -58,6 +58,10 @@ if(WITH_IMAGE_OPENEXR)
        add_definitions(-DWITH_OPENEXR)
 endif()
 
+if(WITH_IMAGE_PSD)
+       add_definitions(-DWITH_PSD)
+endif()
+
 if(WITH_IMAGE_TIFF)
        add_definitions(-DWITH_TIFF)
 endif()
index 6509af179e76d383f646e5c6fc5513de054788b9..fdc1960d1283d5c4eb1ba6738ccc57dd0d508cda 100644 (file)
@@ -58,6 +58,9 @@ if(WITH_IMAGE_OPENEXR)
        add_definitions(-DWITH_OPENEXR)
 endif()
 
+if(WITH_IMAGE_PSD)
+       add_definitions(-DWITH_PSD)
+endif()
 if(WITH_IMAGE_TIFF)
        add_definitions(-DWITH_TIFF)
 endif()
index 29ed8c95fc60b9a5df3665e1de696e5f651b923f..58738155c5049ed485d2922d240eaf5fef39c251 100644 (file)
@@ -105,6 +105,15 @@ if(WITH_IMAGE_TIFF)
        add_definitions(-DWITH_TIFF)
 endif()
 
+
+if(WITH_IMAGE_PSD)
+       add_definitions(-DWITH_PSD)
+else()
+       list(APPEND SRC
+               intern/oiio/openimageio_stub.cpp
+       )
+endif()
+
 if(WITH_IMAGE_OPENJPEG)
        list(APPEND INC_SYS
                ${OPENJPEG_INCLUDE_DIRS}
index 8c2e79ab7d837ce7d8bd84246e754c3185edb54b..c70ab5d7189d1b7131c0951c09368568ceb69691 100644 (file)
@@ -429,7 +429,7 @@ void IMB_alpha_under_color_byte(unsigned char *rect, int x, int y, float backcol
  *
  * \attention defined in readimage.c
  */  
-struct ImBuf *IMB_loadifffile(int file, int flags, char colorspace[IM_MAX_SPACE], const char *descr);
+struct ImBuf *IMB_loadifffile(int file, const char *filepath, int flags, char colorspace[IM_MAX_SPACE], const char *descr);
 
 /**
  *
index 1734073dd6c2e4cefc6fb5ecdfac1c95eb45ed34..df9101247d5fe9d496fd54d92618342aab7cd7c2 100644 (file)
@@ -180,6 +180,10 @@ typedef struct ImBuf {
  */
 #define IB_CUSTOM_FLAGS_MASK 0x7ff
 
+#ifdef WITH_PSD
+#define PSD                            (1 << 31)
+#endif
+
 #define PNG                            (1 << 30)
 #define TGA                            (1 << 28)
 #define JPG                            (1 << 27)
@@ -273,6 +277,9 @@ extern const char *imb_ext_image_qt[];
 extern const char *imb_ext_movie[];
 extern const char *imb_ext_audio[];
 
+/* image formats that can only be loaded via filepath */
+extern const char *imb_ext_image_filepath_only[];
+
 enum {
        IMB_COLORMANAGE_IS_DATA = (1 << 0)
 };
index 3c8b29cf68a9a521628eec79d7aab976f72a3d2a..9327c15c4156e54aae8e32d8ead5c4bf9c234d6d 100644 (file)
@@ -39,8 +39,10 @@ typedef struct ImFileType {
        void (*exit)(void);
 
        int (*is_a)(unsigned char *buf);
+       int (*is_a_filepath)(const char *name);
        int (*ftype)(struct ImFileType *type, struct ImBuf *ibuf);
        struct ImBuf *(*load)(unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE]);
+       struct ImBuf *(*load_filepath)(const char *name, int flags, char colorspace[IM_MAX_SPACE]);
        int (*save)(struct ImBuf *ibuf, const char *name, int flags);
        void (*load_tile)(struct ImBuf *ibuf, unsigned char *mem, size_t size, int tx, int ty, unsigned int *rect);
 
@@ -50,6 +52,7 @@ typedef struct ImFileType {
 } ImFileType;
 
 extern ImFileType IMB_FILE_TYPES[];
+extern ImFileType *IMB_FILE_TYPES_LAST;
 
 void imb_filetypes_init(void);
 void imb_filetypes_exit(void);
index 366c2922739ab218ac0402b8675f2e4a0a2dbc4a..61051464c7f53c1be455789830abe1ec97b43ef5 100644 (file)
@@ -1915,7 +1915,7 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, bool save_as_render, boo
                 * we need to allocate byte buffer and store color managed
                 * image there
                 */
-               for (type = IMB_FILE_TYPES; type->is_a; type++) {
+               for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) {
                        if (type->save && type->ftype(type, colormanaged_ibuf)) {
                                if ((type->flag & IM_FTYPE_FLOAT) == 0)
                                        make_byte = true;
@@ -2451,7 +2451,7 @@ void IMB_colormanagment_colorspace_from_ibuf_ftype(ColorManagedColorspaceSetting
 {
        ImFileType *type;
 
-       for (type = IMB_FILE_TYPES; type->is_a; type++) {
+       for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) {
                if (type->save && type->ftype(type, ibuf)) {
                        const char *role_colorspace;
 
index 37070c7e2bfe2efe683122ec13ff534b0f0cf5cf..4db47646092a25576f85a79bba1a2b2fd9ec30fd 100644 (file)
 #include "openexr/openexr_api.h"
 #endif
 
+#ifdef WITH_PSD
+#include "oiio/openimageio_api.h"
+#endif
+
 #ifdef WITH_DDS
 #include "dds/dds_api.h"
 #endif
@@ -71,41 +75,46 @@ void quicktime_exit(void);
 #endif
 
 ImFileType IMB_FILE_TYPES[] = {
-       {NULL, NULL, imb_is_a_jpeg, imb_ftype_default, imb_load_jpeg, imb_savejpeg, NULL, 0, JPG, COLOR_ROLE_DEFAULT_BYTE},
-       {NULL, NULL, imb_is_a_png, imb_ftype_default, imb_loadpng, imb_savepng, NULL, 0, PNG, COLOR_ROLE_DEFAULT_BYTE},
-       {NULL, NULL, imb_is_a_bmp, imb_ftype_default, imb_bmp_decode, imb_savebmp, NULL, 0, BMP, COLOR_ROLE_DEFAULT_BYTE},
-       {NULL, NULL, imb_is_a_targa, imb_ftype_default, imb_loadtarga, imb_savetarga, NULL, 0, TGA, COLOR_ROLE_DEFAULT_BYTE},
-       {NULL, NULL, imb_is_a_iris, imb_ftype_iris, imb_loadiris, imb_saveiris, NULL, 0, IMAGIC, COLOR_ROLE_DEFAULT_BYTE},
+       {NULL, NULL, imb_is_a_jpeg, NULL, imb_ftype_default, imb_load_jpeg, NULL, imb_savejpeg, NULL, 0, JPG, COLOR_ROLE_DEFAULT_BYTE},
+       {NULL, NULL, imb_is_a_png, NULL, imb_ftype_default, imb_loadpng, NULL, imb_savepng, NULL, 0, PNG, COLOR_ROLE_DEFAULT_BYTE},
+       {NULL, NULL, imb_is_a_bmp, NULL, imb_ftype_default, imb_bmp_decode, NULL, imb_savebmp, NULL, 0, BMP, COLOR_ROLE_DEFAULT_BYTE},
+       {NULL, NULL, imb_is_a_targa, NULL, imb_ftype_default, imb_loadtarga, NULL, imb_savetarga, NULL, 0, TGA, COLOR_ROLE_DEFAULT_BYTE},
+       {NULL, NULL, imb_is_a_iris, NULL, imb_ftype_iris, imb_loadiris, NULL, imb_saveiris, NULL, 0, IMAGIC, COLOR_ROLE_DEFAULT_BYTE},
 #ifdef WITH_CINEON
-       {NULL, NULL, imb_is_dpx, imb_ftype_default, imb_load_dpx, imb_save_dpx, NULL, IM_FTYPE_FLOAT, DPX, COLOR_ROLE_DEFAULT_FLOAT},
-       {NULL, NULL, imb_is_cineon, imb_ftype_default, imb_load_cineon, imb_save_cineon, NULL, IM_FTYPE_FLOAT, CINEON, COLOR_ROLE_DEFAULT_FLOAT},
+       {NULL, NULL, imb_is_dpx, NULL, imb_ftype_default, imb_load_dpx, NULL, imb_save_dpx, NULL, IM_FTYPE_FLOAT, DPX, COLOR_ROLE_DEFAULT_FLOAT},
+       {NULL, NULL, imb_is_cineon, NULL, imb_ftype_default, imb_load_cineon, NULL, imb_save_cineon, NULL, IM_FTYPE_FLOAT, CINEON, COLOR_ROLE_DEFAULT_FLOAT},
 #endif
 #ifdef WITH_TIFF
-       {imb_inittiff, NULL, imb_is_a_tiff, imb_ftype_default, imb_loadtiff, imb_savetiff, imb_loadtiletiff, 0, TIF, COLOR_ROLE_DEFAULT_BYTE},
+       {imb_inittiff, NULL, imb_is_a_tiff, NULL, imb_ftype_default, imb_loadtiff, NULL, imb_savetiff, imb_loadtiletiff, 0, TIF, COLOR_ROLE_DEFAULT_BYTE},
 #endif
 #ifdef WITH_HDR
-       {NULL, NULL, imb_is_a_hdr, imb_ftype_default, imb_loadhdr, imb_savehdr, NULL, IM_FTYPE_FLOAT, RADHDR, COLOR_ROLE_DEFAULT_FLOAT},
+       {NULL, NULL, imb_is_a_hdr, NULL, imb_ftype_default, imb_loadhdr, NULL, imb_savehdr, NULL, IM_FTYPE_FLOAT, RADHDR, COLOR_ROLE_DEFAULT_FLOAT},
 #endif
 #ifdef WITH_OPENEXR
-       {imb_initopenexr, NULL, imb_is_a_openexr, imb_ftype_default, imb_load_openexr, imb_save_openexr, NULL, IM_FTYPE_FLOAT, OPENEXR, COLOR_ROLE_DEFAULT_FLOAT},
+       {imb_initopenexr, NULL, imb_is_a_openexr, NULL, imb_ftype_default, imb_load_openexr, NULL, imb_save_openexr, NULL, IM_FTYPE_FLOAT, OPENEXR, COLOR_ROLE_DEFAULT_FLOAT},
 #endif
 #ifdef WITH_OPENJPEG
-       {NULL, NULL, imb_is_a_jp2, imb_ftype_default, imb_jp2_decode, imb_savejp2, NULL, IM_FTYPE_FLOAT, JP2, COLOR_ROLE_DEFAULT_BYTE},
+       {NULL, NULL, imb_is_a_jp2, NULL, NULL, imb_ftype_default, imb_jp2_decode, NULL, imb_savejp2, NULL, IM_FTYPE_FLOAT, JP2, COLOR_ROLE_DEFAULT_BYTE},
 #endif
 #ifdef WITH_DDS
-       {NULL, NULL, imb_is_a_dds, imb_ftype_default, imb_load_dds, NULL, NULL, 0, DDS, COLOR_ROLE_DEFAULT_BYTE},
+       {NULL, NULL, imb_is_a_dds, NULL, imb_ftype_default, imb_load_dds, NULL, NULL, NULL, 0, DDS, COLOR_ROLE_DEFAULT_BYTE},
 #endif
 #ifdef WITH_QUICKTIME
-       {quicktime_init, quicktime_exit, imb_is_a_quicktime, imb_ftype_quicktime, imb_quicktime_decode, NULL, NULL, 0, QUICKTIME, COLOR_ROLE_DEFAULT_BYTE},
+       {quicktime_init, quicktime_exit, imb_is_a_quicktime, NULL, imb_ftype_quicktime, imb_quicktime_decode, NULL, NULL, 0, QUICKTIME, COLOR_ROLE_DEFAULT_BYTE},
+#endif
+#ifdef WITH_PSD
+       {NULL, NULL, NULL, imb_is_a_photoshop, imb_ftype_default, NULL, imb_load_photoshop, NULL, NULL, IM_FTYPE_FLOAT, PSD, COLOR_ROLE_DEFAULT_FLOAT},
 #endif
-       {NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0}
+       {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0}
 };
-       
+
+ImFileType *IMB_FILE_TYPES_LAST = &IMB_FILE_TYPES[sizeof(IMB_FILE_TYPES)/sizeof(ImFileType)-1];
+
 void imb_filetypes_init(void)
 {
        ImFileType *type;
 
-       for (type = IMB_FILE_TYPES; type->is_a; type++)
+       for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++)
                if (type->init)
                        type->init();
 }
@@ -114,7 +123,7 @@ void imb_filetypes_exit(void)
 {
        ImFileType *type;
 
-       for (type = IMB_FILE_TYPES; type->is_a; type++)
+       for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++)
                if (type->exit)
                        type->exit();
 }
diff --git a/source/blender/imbuf/intern/oiio/CMakeLists.txt b/source/blender/imbuf/intern/oiio/CMakeLists.txt
new file mode 100644 (file)
index 0000000..f5ee5eb
--- /dev/null
@@ -0,0 +1,54 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# 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 2
+# 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, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2013, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s):
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+       .
+       ..
+       ../..
+       ../../../blenkernel
+       ../../../blenlib
+       ../../../makesdna
+       ../../../../../intern/guardedalloc
+       ../../../../../intern/utfconv
+)
+
+set(INC_SYS
+
+)
+
+set(SRC
+       openimageio_api.h
+
+       openimageio_api.cpp
+)
+
+if(WITH_IMAGE_PSD)
+       list(APPEND INC_SYS
+               ${OPENIMAGEIO_INCLUDE_DIRS}
+       )
+       add_definitions(-DWITH_PSD)
+endif()
+
+blender_add_lib(bf_imbuf_openimageio "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/imbuf/intern/oiio/SConscript b/source/blender/imbuf/intern/oiio/SConscript
new file mode 100644 (file)
index 0000000..124f8fb
--- /dev/null
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+#
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# 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 2
+# 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, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2013, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s):
+#
+# ***** END GPL LICENSE BLOCK *****
+
+Import ('env')
+
+source_files = ['openimageio_api.cpp']
+
+incs = ['.',
+    '../../../blenkernel',
+    '../../',
+    '..',
+    '../../../blenlib',
+    'intern/include',
+    '#/intern/guardedalloc',
+    '../../../makesdna',
+    '#/intern/utfconv']
+
+defs = ['WITH_PSD']
+
+if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'):
+    incs.append(env['BF_PTHREADS_INC'])
+
+env.BlenderLib ('bf_imbuf_openimageio', source_files, incs, defs, libtype=['core','player'], priority = [225,180])
diff --git a/source/blender/imbuf/intern/oiio/openimageio_api.cpp b/source/blender/imbuf/intern/oiio/openimageio_api.cpp
new file mode 100644 (file)
index 0000000..3253cf9
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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 2
+ * 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, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Dalai Felinto and Brecht van Lommel
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/imbuf/intern/oiio/openimageio_api.h
+ *  \ingroup openimageio
+ */
+
+#include <set>
+
+#include <openimageio_api.h>
+#include <OpenImageIO/imageio.h>
+
+OIIO_NAMESPACE_USING
+
+#if defined (WIN32) && !defined(FREE_WINDOWS)
+#include "utfconv.h"
+#endif
+
+extern "C"
+{
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+#include "IMB_allocimbuf.h"
+#include "IMB_colormanagement.h"
+#include "IMB_colormanagement_intern.h"
+}
+
+using namespace std;
+
+typedef unsigned char uchar;
+
+template <class T, class Q>
+static void
+fill_all_channels(T * pixels, int width, int height, int components, Q alpha)
+{
+       if(components == 2) {
+               for(int i = width*height-1; i >= 0; i--) {
+                       pixels[i*4+3] = pixels[i*2+1];
+                       pixels[i*4+2] = pixels[i*2+0];
+                       pixels[i*4+1] = pixels[i*2+0];
+                       pixels[i*4+0] = pixels[i*2+0];
+               }
+       }
+       else if(components == 3) {
+               for(int i = width*height-1; i >= 0; i--) {
+                       pixels[i*4+3] = alpha;
+                       pixels[i*4+2] = pixels[i*3+2];
+                       pixels[i*4+1] = pixels[i*3+1];
+                       pixels[i*4+0] = pixels[i*3+0];
+
+               }
+       }
+       else if(components == 1) {
+               for(int i = width*height-1; i >= 0; i--) {
+                       pixels[i*4+3] = alpha;
+                       pixels[i*4+2] = pixels[i];
+                       pixels[i*4+1] = pixels[i];
+                       pixels[i*4+0] = pixels[i];
+               }
+       }
+
+}
+
+static ImBuf *imb_oiio_load_image(ImageInput *in, int width, int height, int components, int flags, bool is_alpha)
+{
+       ImBuf *ibuf;
+       int scanlinesize = width*components*sizeof(uchar);
+
+       /* allocate the memory for the image */
+       ibuf = IMB_allocImBuf(width, height, is_alpha ? 32 : 24, flags|IB_rect);
+
+       try
+       {
+               in->read_image(TypeDesc::UINT8,
+                                          (uchar *)ibuf->rect + (height-1) * scanlinesize,
+                                          AutoStride,
+                                          -scanlinesize,
+                                          AutoStride);
+       }
+       catch (const std::exception &exc)
+       {
+               std::cerr << exc.what() << std::endl;
+               if (ibuf) IMB_freeImBuf(ibuf);
+
+               return NULL;
+       }
+
+       /* ImBuf always needs 4 channels */
+       fill_all_channels((uchar *)ibuf->rect, width, height, components, 0xFF);
+
+       return ibuf;
+}
+
+static ImBuf *imb_oiio_load_image_float(ImageInput *in, int width, int height, int components, int flags, bool is_alpha)
+{
+       ImBuf *ibuf;
+       int scanlinesize = width*components*sizeof(float);
+
+       /* allocate the memory for the image */
+       ibuf = IMB_allocImBuf(width, height, is_alpha ? 32 : 24, flags|IB_rectfloat);
+
+       try
+       {
+               in->read_image(TypeDesc::FLOAT,
+                              (uchar *)ibuf->rect_float + (height-1) * scanlinesize,
+                              AutoStride,
+                              -scanlinesize,
+                              AutoStride);
+       }
+       catch (const std::exception &exc)
+       {
+               std::cerr << exc.what() << std::endl;
+               if (ibuf) IMB_freeImBuf(ibuf);
+
+               return NULL;
+       }
+
+       /* ImBuf always needs 4 channels */
+       fill_all_channels((float *)ibuf->rect_float, width, height, components, 1.0f);
+
+       /* note: Photoshop 16 bit files never has alpha with it, so no need to handle associated/unassociated alpha */
+       return ibuf;
+}
+
+extern "C"
+{
+
+int imb_is_a_photoshop(const char *filename)
+{
+       const char *photoshop_extension[] = {
+               ".psd",
+               ".pdd",
+               ".psb",
+               NULL
+       };
+
+       return BLI_testextensie_array(filename, photoshop_extension);
+}
+
+int imb_save_photoshop(struct ImBuf *ibuf, const char *name, int flags)
+{
+       if (flags & IB_mem) {
+               printf("Photoshop PSD-save: Create PSD in memory CURRENTLY NOT SUPPORTED !\n");
+               imb_addencodedbufferImBuf(ibuf);
+               ibuf->encodedsize = 0;
+               return(0);
+       }
+
+       return(0);
+}
+
+struct ImBuf *imb_load_photoshop (const char *filename, int flags, char colorspace[IM_MAX_SPACE])
+{
+       ImageInput *in = NULL;
+       struct ImBuf *ibuf = NULL;
+       int width, height, components;
+       bool is_float, is_alpha;
+       TypeDesc typedesc;
+       int basesize;
+
+       /* load image from file through OIIO */
+       if (imb_is_a_photoshop(filename) == 0) return (NULL);
+
+       colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
+
+       in = ImageInput::create(filename);
+       if (!in) return NULL;
+
+       ImageSpec spec, config;
+       config.attribute ("oiio:UnassociatedAlpha", (int) 1);
+
+       if(!in->open(filename, spec, config)) {
+               delete in;
+               return NULL;
+       }
+
+       string ics = spec.get_string_attribute("oiio:ColorSpace");
+       BLI_strncpy(colorspace, ics.c_str(), IM_MAX_SPACE);
+
+       width = spec.width;
+       height = spec.height;
+       components = spec.nchannels;
+       is_alpha = spec.alpha_channel != -1;
+       basesize = spec.format.basesize();
+       is_float = basesize > 1;
+
+       /* we only handle certain number of components */
+       if(!(components >= 1 && components <= 4)) {
+               if(in) {
+                       in->close();
+                       delete in;
+               }
+               return NULL;
+       }
+
+       if (is_float)
+               ibuf = imb_oiio_load_image_float(in, width, height, components, flags, is_alpha);
+       else
+               ibuf = imb_oiio_load_image(in, width, height, components, flags, is_alpha);
+
+       if (in) {
+               in->close();
+               delete in;
+       }
+
+       if (!ibuf)
+               return NULL;
+
+       /* ImBuf always needs 4 channels */
+       ibuf->ftype = PSD;
+       ibuf->channels = 4;
+       ibuf->planes = (3 + (is_alpha ? 1 : 0)) * 4 << basesize;
+
+       try
+       {
+               return(ibuf);
+       }
+       catch (const std::exception &exc)
+       {
+               std::cerr << exc.what() << std::endl;
+               if (ibuf) IMB_freeImBuf(ibuf);
+
+               return (0);
+       }
+}
+
+} // export "C"
+
+
diff --git a/source/blender/imbuf/intern/oiio/openimageio_api.h b/source/blender/imbuf/intern/oiio/openimageio_api.h
new file mode 100644 (file)
index 0000000..ce96e27
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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 2
+ * 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, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s):
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/imbuf/intern/oiio/openimageio_api.h
+ *  \ingroup openimageio
+ */
+
+
+#ifndef __OIIO_API_H__
+#define __OIIO_API_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+
+int            imb_is_a_photoshop                      (const char *name);
+
+int            imb_save_photoshop                      (struct ImBuf *ibuf, const char *name, int flags);
+
+struct ImBuf *imb_load_photoshop (const char *name, int flags, char *colorspace);
+
+#ifdef __cplusplus
+}
+
+#endif
+
+#endif /* __OIIO_API_H */
diff --git a/source/blender/imbuf/intern/oiio/openimageio_stub.cpp b/source/blender/imbuf/intern/oiio/openimageio_stub.cpp
new file mode 100644 (file)
index 0000000..b57de0b
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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 2
+ * 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, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s):
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+
+/** \file blender/imbuf/intern/oiio/openimageio_api.h
+ *  \ingroup openimageio
+ */
+
+#include "openimageio_api.h"
+
+#endif
index d73fa9a7ab72dd878137f78f9933d139cfcc1560..6988687e4ed4dbba5670e65e8eff4b2750a5c7b6 100644 (file)
 #include "IMB_colormanagement.h"
 #include "IMB_colormanagement_intern.h"
 
+static void imb_handle_alpha(ImBuf *ibuf, int flags, char colorspace[IM_MAX_SPACE], char effective_colorspace[IM_MAX_SPACE])
+{
+       int alpha_flags;
+
+       if (colorspace) {
+               if (ibuf->rect) {
+                       /* byte buffer is never internally converted to some standard space,
+                        * store pointer to it's color space descriptor instead
+                        */
+                       ibuf->rect_colorspace = colormanage_colorspace_get_named(effective_colorspace);
+               }
+
+               BLI_strncpy(colorspace, effective_colorspace, IM_MAX_SPACE);
+       }
+
+       if (flags & IB_alphamode_detect)
+               alpha_flags = ibuf->flags & IB_alphamode_premul;
+       else
+               alpha_flags = flags & IB_alphamode_premul;
+
+       if (flags & IB_ignore_alpha) {
+               IMB_rectfill_alpha(ibuf, 1.0f);
+       }
+       else {
+               if (alpha_flags & IB_alphamode_premul) {
+                       if (ibuf->rect) {
+                               IMB_unpremultiply_alpha(ibuf);
+                       }
+                       else {
+                               /* pass, floats are expected to be premul */
+                       }
+               }
+               else {
+                       if (ibuf->rect_float) {
+                               IMB_premultiply_alpha(ibuf);
+                       }
+                       else {
+                               /* pass, bytes are expected to be straight */
+                       }
+               }
+       }
+
+       /* OCIO_TODO: in some cases it's faster to do threaded conversion,
+        *            but how to distinguish such cases */
+       colormanage_imbuf_make_linear(ibuf, effective_colorspace);
+}
+
 ImBuf *IMB_ibImageFromMemory(unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE], const char *descr)
 {
        ImBuf *ibuf;
@@ -70,54 +117,36 @@ ImBuf *IMB_ibImageFromMemory(unsigned char *mem, size_t size, int flags, char co
        if (colorspace)
                BLI_strncpy(effective_colorspace, colorspace, sizeof(effective_colorspace));
 
-       for (type = IMB_FILE_TYPES; type->is_a; type++) {
+       for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) {
                if (type->load) {
                        ibuf = type->load(mem, size, flags, effective_colorspace);
                        if (ibuf) {
-                               int alpha_flags;
-
-                               if (colorspace) {
-                                       if (ibuf->rect) {
-                                               /* byte buffer is never internally converted to some standard space,
-                                                * store pointer to it's color space descriptor instead
-                                                */
-                                               ibuf->rect_colorspace = colormanage_colorspace_get_named(effective_colorspace);
-                                       }
-
-                                       BLI_strncpy(colorspace, effective_colorspace, IM_MAX_SPACE);
-                               }
-
-                               if (flags & IB_alphamode_detect)
-                                       alpha_flags = ibuf->flags & IB_alphamode_premul;
-                               else
-                                       alpha_flags = flags & IB_alphamode_premul;
-
-                               if (flags & IB_ignore_alpha) {
-                                       IMB_rectfill_alpha(ibuf, 1.0f);
-                               }
-                               else {
-                                       if (alpha_flags & IB_alphamode_premul) {
-                                               if (ibuf->rect) {
-                                                       IMB_unpremultiply_alpha(ibuf);
-                                               }
-                                               else {
-                                                       /* pass, floats are expected to be premul */
-                                               }
-                                       }
-                                       else {
-                                               if (ibuf->rect_float) {
-                                                       IMB_premultiply_alpha(ibuf);
-                                               }
-                                               else {
-                                                       /* pass, bytes are expected to be straight */
-                                               }
-                                       }
-                               }
-
-                               /* OCIO_TODO: in some cases it's faster to do threaded conversion,
-                                *            but how to distinguish such cases */
-                               colormanage_imbuf_make_linear(ibuf, effective_colorspace);
+                               imb_handle_alpha(ibuf, flags, colorspace, effective_colorspace);
+                               return ibuf;
+                       }
+               }
+       }
+
+       if ((flags & IB_test) == 0)
+               fprintf(stderr, "%s: unknown fileformat (%s)\n", __func__, descr);
+
+       return NULL;
+}
+
+static ImBuf *IMB_ibImageFromFile(const char *filepath, int flags, char colorspace[IM_MAX_SPACE], const char *descr)
+{
+       ImBuf *ibuf;
+       ImFileType *type;
+       char effective_colorspace[IM_MAX_SPACE] = "";
+
+       if (colorspace)
+               BLI_strncpy(effective_colorspace, colorspace, sizeof(effective_colorspace));
 
+       for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) {
+               if (type->load_filepath) {
+                       ibuf = type->load_filepath(filepath, flags, effective_colorspace);
+                       if (ibuf) {
+                               imb_handle_alpha(ibuf, flags, colorspace, effective_colorspace);
                                return ibuf;
                        }
                }
@@ -129,7 +158,13 @@ ImBuf *IMB_ibImageFromMemory(unsigned char *mem, size_t size, int flags, char co
        return NULL;
 }
 
-ImBuf *IMB_loadifffile(int file, int flags, char colorspace[IM_MAX_SPACE], const char *descr)
+static bool imb_is_filepath_format(const char *filepath)
+{
+       /* return true if this is one of the formats that can't be loaded from memory */
+       return BLI_testextensie_array(filepath, imb_ext_image_filepath_only);
+}
+
+ImBuf *IMB_loadifffile(int file, const char *filepath, int flags, char colorspace[IM_MAX_SPACE], const char *descr)
 {
        ImBuf *ibuf;
        unsigned char *mem;
@@ -137,6 +172,9 @@ ImBuf *IMB_loadifffile(int file, int flags, char colorspace[IM_MAX_SPACE], const
 
        if (file == -1) return NULL;
 
+       if (imb_is_filepath_format(filepath))
+               return IMB_ibImageFromFile(filepath, flags, colorspace, descr);
+
        size = BLI_file_descriptor_size(file);
 
        mem = mmap(NULL, size, PROT_READ, MAP_SHARED, file, 0);
@@ -179,7 +217,7 @@ ImBuf *IMB_loadiffname(const char *filepath, int flags, char colorspace[IM_MAX_S
        file = BLI_open(filepath_tx, O_BINARY | O_RDONLY, 0);
        if (file < 0) return NULL;
 
-       ibuf = IMB_loadifffile(file, flags, colorspace, filepath_tx);
+       ibuf = IMB_loadifffile(file, filepath, flags, colorspace, filepath_tx);
 
        if (ibuf) {
                BLI_strncpy(ibuf->name, filepath, sizeof(ibuf->name));
@@ -206,7 +244,7 @@ ImBuf *IMB_testiffname(const char *filepath, int flags)
        file = BLI_open(filepath_tx, O_BINARY | O_RDONLY, 0);
        if (file < 0) return NULL;
 
-       ibuf = IMB_loadifffile(file, flags | IB_test | IB_multilayer, colorspace, filepath_tx);
+       ibuf = IMB_loadifffile(file, filepath, flags | IB_test | IB_multilayer, colorspace, filepath_tx);
 
        if (ibuf) {
                BLI_strncpy(ibuf->name, filepath, sizeof(ibuf->name));
@@ -234,7 +272,7 @@ static void imb_loadtilefile(ImBuf *ibuf, int file, int tx, int ty, unsigned int
                return;
        }
 
-       for (type = IMB_FILE_TYPES; type->is_a; type++)
+       for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++)
                if (type->load_tile && type->ftype(type, ibuf))
                        type->load_tile(ibuf, mem, size, tx, ty, rect);
 
index a4b0e61d544dec8357f9889a2329479525283f55..434a1717bc8d5aecd919d7ee20a55791b7b6fe68 100644 (file)
@@ -97,6 +97,16 @@ const char *imb_ext_image[] = {
 #endif
 #ifdef WITH_OPENEXR
        ".exr",
+#endif
+#ifdef WITH_PSD
+       ".psd", ".pdd", ".psb",
+#endif
+       NULL
+};
+
+const char *imb_ext_image_filepath_only[] = {
+#ifdef WITH_PSD
+       ".psd", ".pdd", ".psb",
 #endif
        NULL
 };
@@ -188,9 +198,16 @@ static int IMB_ispic_name(const char *name)
        if ((BIG_LONG(((int *)buf)[0]) & 0xfffffff0) == 0xffd8ffe0)
                return JPG;
 
-       for (type = IMB_FILE_TYPES; type->is_a; type++) {
-               if (type->is_a(buf)) {
-                       return type->filetype;
+       for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) {
+               if (type->is_a) {
+                       if (type->is_a(buf)) {
+                               return type->filetype;
+                       }
+               }
+               else if (type->is_a_filepath) {
+                       if (type->is_a_filepath(name)) {
+                               return type->filetype;
+                       }
                }
        }
 
index 5d785e08212778982537faa332e0bcc4f73411b5..1519fc1990d67b57b4c74d6c04e4973bf165e33b 100644 (file)
@@ -67,7 +67,7 @@ short IMB_saveiff(struct ImBuf *ibuf, const char *name, int flags)
        if (ibuf == NULL) return (FALSE);
        ibuf->flags = flags;
 
-       for (type = IMB_FILE_TYPES; type->is_a; type++) {
+       for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) {
                if (type->save && type->ftype(type, ibuf)) {
                        ImBuf *write_ibuf;
                        short result = FALSE;
index e8f55ac047ce13a54d5a4986122dc574ebf41003..35bd46507760afec220ed0fe4603c80eed4585c5 100644 (file)
@@ -316,6 +316,7 @@ typedef struct ImageFormatData {
 #define R_IMF_IMTYPE_H264           31
 #define R_IMF_IMTYPE_XVID           32
 #define R_IMF_IMTYPE_THEORA         33
+#define R_IMF_IMTYPE_PSD            34
 
 #define R_IMF_IMTYPE_INVALID        255
 
index d901897cbc420ca2e10b166c031dc64da4a116f9..9554941ec1fc8114719ef3a2de157b067f263928 100644 (file)
@@ -164,6 +164,10 @@ if(WITH_IMAGE_OPENEXR)
        add_definitions(-DWITH_OPENEXR)
 endif()
 
+if(WITH_IMAGE_PSD)
+       add_definitions(-DWITH_PSD)
+endif()
+
 if(WITH_IMAGE_TIFF)
        add_definitions(-DWITH_TIFF)
 endif()
index 0cfb399c470fec9ff48e5220e219fe95f375c67c..9414591eaf923e978e7c663a85d14cb9adde1fa8 100644 (file)
@@ -219,6 +219,13 @@ EnumPropertyItem snap_uv_element_items[] = {
 #  define R_IMF_ENUM_TIFF
 #endif
 
+#ifdef WITH_PSD
+#  define R_IMF_ENUM_PSD     {R_IMF_IMTYPE_PSD, "PSD", ICON_FILE_IMAGE, "Photosp PSD", \
+                                                "Output image in Photoshop PSD format"},
+#else
+#  define R_IMF_ENUM_PSD
+#endif
+
 
 #define IMAGE_TYPE_ITEMS_IMAGE_ONLY                                           \
        R_IMF_ENUM_BMP                                                            \
@@ -236,6 +243,7 @@ EnumPropertyItem snap_uv_element_items[] = {
        R_IMF_ENUM_EXR                                                            \
        R_IMF_ENUM_HDR                                                            \
        R_IMF_ENUM_TIFF                                                           \
+       R_IMF_ENUM_PSD                                                            \
 
 
 EnumPropertyItem image_only_type_items[] = {
index aae0f926e8119c566cb52d1556dd2984c182e38f..072c73d3d499167533e1be139868cebb2cfef0bf 100644 (file)
@@ -174,6 +174,10 @@ if(WITH_IMAGE_OPENEXR)
        add_definitions(-DWITH_OPENEXR)
 endif()
 
+if(WITH_IMAGE_PSD)
+       add_definitions(-DWITH_PSD)
+endif()
+
 if(WITH_IMAGE_OPENJPEG)
        add_definitions(-DWITH_OPENJPEG)
 endif()
index d91319d7477f6f8cff0a4b6ed12f7f91784ba95f..67009bf2c8b38a3615dd49b918fe1d4ec7311f50 100644 (file)
@@ -129,6 +129,7 @@ endif()
                bf_intern_utfconv
                bf_imbuf_cineon
                bf_imbuf_openexr 
+               bf_imbuf_openimageio
                extern_openjpeg
                extern_redcode
                bf_imbuf_dds
index b24339cff1bd9cb7c8902b2f35e8175079fa4435..8e0ba6684abd4e268e8d5b3c02315f0985a755b5 100644 (file)
@@ -912,6 +912,7 @@ endif()
                bf_avi
                bf_imbuf_cineon
                bf_imbuf_openexr
+               bf_imbuf_openimageio
                bf_imbuf_dds
                bf_collada
                bf_intern_bsp