diff --git a/configure.ac b/configure.ac
index f49c762..bb10328 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1772,6 +1772,21 @@ PKG_CHECK_MODULES(LCMS, lcms2 >= lcms_required_version,,
 
 
 ######################
+# Check for file-cmyk
+######################
+
+if test -n "$TIFF_LIBS" && test -n "$JPEG_LIBS" && test -n "$LCMS_LIBS"; then
+  FILE_CMYK_SAVE='file-cmyk-save$(EXEEXT)'
+  FILE_CMYK_CFLAGS="$LCMS_CFLAGS"
+  FILE_CMYK_LIBS="$TIFF_LIBS $JPEG_LIBS $LCMS_LIBS"
+fi
+
+AC_SUBST(FILE_CMYK_SAVE)
+AC_SUBST(FLIE_CMYK_CFLAGS)
+AC_SUBST(FILE_CMYK_LIBS)
+
+
+######################
 # Check for libXcursor
 ######################
 
diff --git a/plug-ins/common/Makefile.am b/plug-ins/common/Makefile.am
index 318bedc..7a61298 100644
--- a/plug-ins/common/Makefile.am
+++ b/plug-ins/common/Makefile.am
@@ -76,6 +76,7 @@ libexec_PROGRAMS = \
 	emboss \
 	$(FILE_AA) \
 	file-cel \
+	$(FILE_CMYK_SAVE) \
 	file-compressor \
 	file-csource \
 	file-desktop-link \
@@ -145,6 +146,7 @@ libexec_PROGRAMS = \
 
 EXTRA_PROGRAMS = \
 	file-aa \
+	file-cmyk-save \
 	file-jp2-load \
 	file-mng \
 	file-pdf-load \
@@ -628,6 +630,27 @@ file_cel_LDADD = \
 	$(RT_LIBS)		\
 	$(INTLLIBS)		\
 	$(file_cel_RC)
+ 
+file_cmyk_save_CFLAGS = $(FILE_CMYK_CFLAGS)
+
+file_cmyk_save_SOURCES = \
+	file-cmyk-save.c
+
+file_cmyk_save_LDADD = \
+	$(libgimpui)		\
+	$(libgimpwidgets)	\
+	$(libgimpmodule)	\
+	$(libgimp)		\
+	$(libgimpmath)		\
+	$(libgimpconfig)	\
+	$(libgimpcolor)		\
+	$(libgimpbase)		\
+	$(GTK_LIBS)		\
+	$(GEGL_LIBS)		\
+	$(FILE_CMYK_LIBS)	\
+	$(RT_LIBS)		\
+	$(INTLLIBS)		\
+	$(file_cmyk_save_RC)
 
 file_compressor_CFLAGS = $(LZMA_CFLAGS)
 
diff --git a/plug-ins/common/file-cmyk-save.c b/plug-ins/common/file-cmyk-save.c
new file mode 100644
index 0000000..cdb901a
--- /dev/null
+++ b/plug-ins/common/file-cmyk-save.c
@@ -0,0 +1,1265 @@
+/* separate- : CMYK file export plug-in
+ *
+ * by Yoshinori Yamakawa
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <glib/gstdio.h>
+
+#include "libgimp/gimp.h"
+#include "libgimp/gimpui.h"
+
+#include <lcms2.h>
+#include <tiffio.h>
+#include <jpeglib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <setjmp.h>
+
+#include "libgimp/stdplugins-intl.h"
+
+
+#define TIFF_SAVE_PROC "file-cmyk-tiff-save"
+#define JPEG_SAVE_PROC "file-cmyk-jpeg-save"
+#define PSD_SAVE_PROC  "file-cmyk-psd-save"
+#define PLUG_IN_BINARY "file-cmyk-save"
+
+
+#define PSD_MAX_PIXELS 30000
+
+
+typedef enum _SeparateFileType
+{
+  FILE_TYPE_TIFF = 0,
+  FILE_TYPE_JPEG = 1,
+  FILE_TYPE_PSD  = 2
+} SeparateFileType;
+
+const gchar *SeparateFileTypeDescription[] =
+{
+  N_("TIFF (CMYK)"),
+  N_("JPEG (CMYK)"),
+  N_("Photoshop PSD (CMYK)")
+};
+
+typedef struct _SeparateSettings
+{
+  gint32            compression;
+  gboolean          embed_profile;
+} SeparateSettings;
+
+typedef struct _SeparateContext
+{
+  const gchar      *proc_name;
+
+  gint32            image_id;
+  gint32            drawable_id;
+  gint32            width;
+  gint32            height;
+
+  GimpColorRenderingIntent intent;
+  gboolean          bpc;
+  GimpColorProfile *source_profile;
+  GimpColorProfile *destination_profile;
+  gconstpointer     destination_profile_data;
+  gsize             destination_profile_length;
+
+  gchar            *filename;
+
+  GString          *message;
+
+  SeparateFileType  filetype;
+  SeparateSettings  settings;
+  gint              compression_type;
+} SeparateContext;
+
+
+static void      query                   (void);
+static void      run                     (const gchar      *name,
+                                          gint              nparams,
+                                          const GimpParam  *param,
+                                          gint             *nreturn_vals,
+                                          GimpParam       **return_vals);
+static gboolean  export_dialog           (SeparateContext  *context);
+static gboolean  export_tiff             (SeparateContext  *context);
+static gboolean  write_tiff_data         (TIFF             *out,
+                                          SeparateContext  *context,
+                                          gint32            width,
+                                          gint32            height);
+static gboolean  export_jpeg             (SeparateContext  *context);
+static void      write_jpeg_profile_data (j_compress_ptr    cinfo,
+                                          const gchar      *profile_data,
+                                          gsize             profile_length);
+static gboolean  write_jpeg_data         (j_compress_ptr    cinfo,
+                                          SeparateContext  *context);
+static gboolean  export_psd              (SeparateContext  *context);
+static gboolean  write_psd_data_packbits (int               fd,
+                                          SeparateContext  *context);
+static gboolean  write_psd_data_raw      (int               fd,
+                                          SeparateContext  *context);
+
+
+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 tiff_save_args[] =
+  {
+    { GIMP_PDB_INT32,    "run-mode",      "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
+    { GIMP_PDB_IMAGE,    "image",         "Input image" },
+    { GIMP_PDB_DRAWABLE, "drawable",      "Drawable to export" },
+    { GIMP_PDB_STRING,   "filename",      "The name of the file to export the image in" },
+    { GIMP_PDB_STRING,   "raw-filename",  "The name of the file to export the image in" },
+    { GIMP_PDB_INT32,    "embed-profile", "Embed color profile" },
+    { GIMP_PDB_INT32,    "compression",   "Compression type: { NONE (0), LZW (1), PACKBITS (2), DEFLATE (3) }" }
+  };
+
+  static const GimpParamDef jpeg_save_args[] =
+  {
+    { GIMP_PDB_INT32,    "run-mode",      "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
+    { GIMP_PDB_IMAGE,    "image",         "Input image" },
+    { GIMP_PDB_DRAWABLE, "drawable",      "Drawable to export" },
+    { GIMP_PDB_STRING,   "filename",      "The name of the file to export the image in" },
+    { GIMP_PDB_STRING,   "raw-filename",  "The name of the file to export the image in" },
+    { GIMP_PDB_INT32,    "embed-profile", "Embed color profile" },
+    { GIMP_PDB_INT32,    "quality",       "Compression quality" }
+  };
+
+  static const GimpParamDef psd_save_args[] =
+  {
+    { GIMP_PDB_INT32,    "run-mode",      "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
+    { GIMP_PDB_IMAGE,    "image",         "Input image" },
+    { GIMP_PDB_DRAWABLE, "drawable",      "Drawable to save" },
+    { GIMP_PDB_STRING,   "filename",      "The name of the file to export the image in" },
+    { GIMP_PDB_STRING,   "raw-filename",  "The name of the file to export the image in" },
+    { GIMP_PDB_INT32,    "embed-profile", "Embed color profile" },
+    { GIMP_PDB_INT32,    "compression",   "Compression { TRUE, FALSE }" }
+  };
+
+  gimp_install_procedure (TIFF_SAVE_PROC,
+                          "exports color separation in the TIFF file format",
+                          "Converts image from RGB to CMYK and\n"
+                          "exports in the TIFF file format.",
+                          "Yoshinori Yamakawa",
+                          "Yoshinori Yamakawa",
+                          "2011-2016",
+                          N_("TIFF image (CMYK)"),
+                          "RGB",
+                          GIMP_PLUGIN,
+                          G_N_ELEMENTS (tiff_save_args), 0,
+                          tiff_save_args, NULL);
+
+  gimp_register_file_handler_mime (TIFF_SAVE_PROC, "image/tiff");
+  gimp_register_save_handler (TIFF_SAVE_PROC, "tif,tiff", "");
+
+  gimp_install_procedure (JPEG_SAVE_PROC,
+                          "exports color separation in the JPEG file format",
+                          "Converts image from RGB to CMYK and\n"
+                          "exports in the JPEG file format.",
+                          "Yoshinori Yamakawa",
+                          "Yoshinori Yamakawa",
+                          "2011-2016",
+                          N_("JPEG image (CMYK)"),
+                          "RGB",
+                          GIMP_PLUGIN,
+                          G_N_ELEMENTS (jpeg_save_args), 0,
+                          jpeg_save_args, NULL);
+
+  gimp_register_file_handler_mime (JPEG_SAVE_PROC, "image/jpeg");
+  gimp_register_save_handler (JPEG_SAVE_PROC, "jpg,jpeg,jpe", "");
+
+  gimp_install_procedure (PSD_SAVE_PROC,
+                          "exports color separation in the Photoshop PSD file format",
+                          "Converts image from RGB to CMYK and\n"
+                          "exports in the Photoshop PSD file format.",
+                          "Yoshinori Yamakawa",
+                          "Yoshinori Yamakawa",
+                          "2011-2016",
+                          N_("PSD image (CMYK)"),
+                          "RGB",
+                          GIMP_PLUGIN,
+                          G_N_ELEMENTS (psd_save_args), 0,
+                          psd_save_args, NULL);
+
+  gimp_register_file_handler_mime (PSD_SAVE_PROC, "image/psd");
+  gimp_register_save_handler (PSD_SAVE_PROC, "psd", "");
+}
+
+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;
+  SeparateContext    context;
+  GimpExportReturn   export = GIMP_EXPORT_CANCEL;
+  GimpColorConfig   *config;
+
+  INIT_I18N ();
+  gegl_init (NULL, NULL);
+
+#if 0
+#ifdef DEBUG
+  cmsErrorAction (LCMS_ERROR_SHOW);
+#else
+  cmsErrorAction (LCMS_ERROR_IGNORE);
+#endif
+#endif
+
+  run_mode = param[0].data.d_int32;
+
+  memset (&context, 0, sizeof (context));
+  context.proc_name   = name;
+  context.image_id    = param[1].data.d_int32;
+  context.drawable_id = param[2].data.d_int32;
+  /*context.drawable    = gimp_drawable_get (context.drawable_id);*/
+  context.width       = gimp_image_width (context.image_id);
+  context.height      = gimp_image_height (context.image_id);
+  context.filename    = param[3].data.d_string;
+
+  context.message = g_string_new ("");
+
+  if (strcmp (name, TIFF_SAVE_PROC) == 0)
+    {
+      context.filetype = FILE_TYPE_TIFF;
+    }
+  else if (strcmp (name, JPEG_SAVE_PROC) == 0)
+    {
+      context.filetype = FILE_TYPE_JPEG;
+      context.settings.compression = 80; /* default quality value */
+    }
+  else if (strcmp (name, PSD_SAVE_PROC) == 0)
+    {
+      context.filetype = FILE_TYPE_PSD;
+
+      if (context.width > PSD_MAX_PIXELS || context.height > PSD_MAX_PIXELS)
+        {
+          g_string_printf (context.message, _("PSD format does not support the images that are more than 30000x30000 pixels."));
+          status = GIMP_PDB_CALLING_ERROR;
+        }
+    }
+  else
+    {
+      g_string_printf (context.message, _("Invalid procedure name : %s"), name);
+      status = GIMP_PDB_CALLING_ERROR;
+    }  
+
+  /* Load the Color Management Preferences and ICC Profiles */
+  if ((config = gimp_get_color_configuration()))
+    {
+      GimpColorManagementMode mode = gimp_color_config_get_mode (config);
+      GError *error = NULL;
+
+      context.source_profile = context.destination_profile = NULL;
+
+      /* load source color profile */
+      context.source_profile = gimp_image_get_effective_color_profile (context.image_id);
+
+      /* get destination color profile */
+      if (mode != GIMP_COLOR_MANAGEMENT_SOFTPROOF ||
+          (context.destination_profile = gimp_color_config_get_simulation_color_profile (config, &error)) == NULL ||
+          ! gimp_color_profile_is_cmyk (context.destination_profile))
+        {
+          g_object_unref (context.destination_profile);
+
+          context.destination_profile = gimp_color_config_get_cmyk_color_profile (config, &error);
+
+          if (! gimp_color_profile_is_cmyk (context.destination_profile))
+          {
+            g_object_unref (context.destination_profile);
+            context.destination_profile = NULL;
+          }
+        }
+
+      context.intent = gimp_color_config_get_simulation_intent (config);
+      context.bpc = gimp_color_config_get_simulation_bpc (config);
+
+      if (! context.destination_profile)
+        {
+          g_string_printf (context.message,
+                           _("Destination profile cannot be loaded or is not CMYK profile.\n"
+                             "Please check the color management preferences."));
+          status = GIMP_PDB_CALLING_ERROR;
+        }
+
+      context.destination_profile_data =
+        gimp_color_profile_get_icc_profile (context.destination_profile, &context.destination_profile_length);
+
+      g_object_unref (G_OBJECT (config));
+      g_error_free (error);
+    }
+  else
+    {
+      g_string_printf (context.message, _("Cannot access the color management preferences."));
+      status = GIMP_PDB_CALLING_ERROR;
+    }
+
+  if (status != GIMP_PDB_SUCCESS)
+    {
+      goto cleanup;
+    }
+
+  if (run_mode == GIMP_RUN_INTERACTIVE ||
+      run_mode == GIMP_RUN_WITH_LAST_VALS)
+    {
+      gimp_get_data (context.proc_name, &context.settings);
+
+      gimp_ui_init (PLUG_IN_BINARY, FALSE);
+
+      export = gimp_export_image (&context.image_id,
+                                  &context.drawable_id,
+                                  NULL,
+                                  GIMP_EXPORT_CAN_HANDLE_RGB);
+
+      if (export == GIMP_EXPORT_CANCEL)
+        {
+          status = GIMP_PDB_CANCEL;
+        }
+      else if (run_mode == GIMP_RUN_INTERACTIVE && ! export_dialog (&context))
+        {
+          status = GIMP_PDB_CANCEL;
+        }
+    }
+  else if (nparams == 7)
+    {
+      context.settings.embed_profile = param[5].data.d_int32;
+      context.settings.compression = param[6].data.d_int32;
+    }
+  else
+    {
+      status = GIMP_PDB_CALLING_ERROR;
+    }
+
+  /* check parameter values */
+  switch (context.filetype)
+    {
+    case FILE_TYPE_TIFF:
+      switch (context.settings.compression)
+        {
+        case 0:
+          context.compression_type = COMPRESSION_NONE;
+          break;
+        case 1:
+          context.compression_type = COMPRESSION_LZW;
+          break;
+        case 2:
+          context.compression_type = COMPRESSION_PACKBITS;
+          break;
+        case 3:
+          context.compression_type = COMPRESSION_DEFLATE;
+          break;
+        default:
+          status = GIMP_PDB_CALLING_ERROR;
+        }
+      break;
+    case FILE_TYPE_JPEG:
+      if (context.settings.compression < 0 || context.settings.compression > 100)
+        {
+          status = GIMP_PDB_CALLING_ERROR;
+        }
+      break;
+    case FILE_TYPE_PSD:
+    default:
+      break;
+    }
+
+  /* export */
+  if (status == GIMP_PDB_SUCCESS)
+    {
+      if ((context.filetype == FILE_TYPE_TIFF && export_tiff (&context)) ||
+          (context.filetype == FILE_TYPE_JPEG && export_jpeg (&context)) ||
+          (context.filetype == FILE_TYPE_PSD && export_psd (&context)))
+        {
+          if (run_mode == GIMP_RUN_INTERACTIVE)
+            {
+              gimp_set_data (context.proc_name, &context.settings, sizeof (context.settings));
+            }
+        }
+      else
+        {
+          status = GIMP_PDB_EXECUTION_ERROR;
+        }
+    }
+
+  if (export == GIMP_EXPORT_EXPORT)
+    gimp_image_delete (context.image_id);
+
+cleanup:
+  if (context.source_profile)
+    {
+      g_object_unref (context.source_profile);
+    }
+  if (context.destination_profile)
+    {
+      g_object_unref (context.destination_profile);
+    }
+
+  *nreturn_vals = 1;
+  *return_vals = values;
+  values[0].type = GIMP_PDB_STATUS;
+  values[0].data.d_status = status;
+
+  if (context.message->len)
+    {
+      *nreturn_vals = 2;
+      values[1].type = GIMP_PDB_STRING;
+      values[1].data.d_string = context.message->str;
+      g_string_free (context.message, FALSE);
+    }
+  else
+    {
+      g_string_free (context.message, TRUE);
+    }
+}
+
+static gboolean
+export_dialog (SeparateContext  *context)
+{
+  GtkWidget *dialog;
+  GtkWidget *vbox;
+  GtkWidget *label;
+  GtkObject *quality = NULL;
+  GtkWidget *compression = NULL;
+  GtkWidget *embed_profile;
+
+  gchar *markup, *source_desc, *intent_desc;
+
+  gboolean run;
+
+  dialog = gimp_export_dialog_new (_(SeparateFileTypeDescription[context->filetype]),
+                                   PLUG_IN_BINARY, context->proc_name);
+
+  vbox = gtk_vbox_new (FALSE, 12);
+  gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
+  gtk_box_pack_start (GTK_BOX (gimp_export_dialog_get_content_area (dialog)),
+                      vbox, FALSE, TRUE, 0);
+
+  switch (context->intent)
+    {
+    case GIMP_COLOR_RENDERING_INTENT_PERCEPTUAL:
+      intent_desc = N_("Perceptual");
+      break;
+    case GIMP_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC:
+      if (context->bpc)
+        intent_desc = N_("Relative colorimetric with BPC");
+      else
+        intent_desc = N_("Relative colorimetric");
+      break;
+    case GIMP_COLOR_RENDERING_INTENT_SATURATION:
+      intent_desc = N_("Saturation");
+      break;
+    case GIMP_COLOR_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC:
+      intent_desc = N_("Absolute colorimetric");
+      break;
+    default:
+      intent_desc = N_("Unknown");
+    }
+
+  source_desc = g_strdup (gimp_color_profile_get_description (context->source_profile));
+
+  markup = g_strdup_printf (_("<b>Convert from:</b>\n  %s\n<b>to:</b>\n  %s\n\n"
+                              "<b>Rendering Intent:</b>\n %s"),
+                            source_desc,
+                            gimp_color_profile_get_description (context->destination_profile),
+                            _(intent_desc));
+
+  label = gtk_label_new (NULL);
+  gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
+  gtk_label_set_markup (GTK_LABEL (label), markup);
+  gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+  g_free (source_desc);
+  g_free (markup);
+
+  if (context->filetype == FILE_TYPE_JPEG)
+    {
+      GtkWidget *table = gtk_table_new (1, 3, FALSE);
+      gtk_table_set_col_spacings (GTK_TABLE (table), 6);
+      gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
+
+      quality = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
+                                      _("_Quality:"),
+                                      0, 0,
+                                      context->settings.compression,
+                                      0.0, 100.0, 1.0, 10.0, 0,
+                                      TRUE, 0.0, 0.0,
+                                      _("JPEG quality parameter"),
+                                      "file-jpeg-save-quality");
+    }
+  else
+    {
+      compression = gtk_check_button_new_with_mnemonic
+        (context->filetype == FILE_TYPE_TIFF ? _("_LZW compression") : _("_Packbits compression"));
+      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (compression), context->settings.compression > 0);
+      gtk_box_pack_start (GTK_BOX (vbox), compression, FALSE, FALSE, 0);
+    }
+
+  embed_profile = gtk_check_button_new_with_mnemonic (_("_Embed color profile"));
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (embed_profile), context->settings.embed_profile);
+  gtk_box_pack_start (GTK_BOX (vbox), embed_profile, FALSE, FALSE, 0);
+
+  gtk_widget_show_all (vbox);
+  gtk_widget_show (dialog);
+
+  if ((run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK)))
+    {
+      context->settings.compression = context->filetype == FILE_TYPE_JPEG ?
+        gtk_range_get_value (GTK_RANGE (GIMP_SCALE_ENTRY_SCALE (quality))) :
+        (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (compression)) ? 1 : 0);
+      context->settings.embed_profile = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (embed_profile));
+    }
+
+  gtk_widget_destroy (dialog);
+
+  return run;
+}
+
+/***** TIFF export functions *****/
+
+#define STRIPHEIGHT 64
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+static gboolean
+export_tiff (SeparateContext  *context)
+{
+  gint32 width, height;
+  gdouble xres, yres;
+  int fd;
+  TIFF *out;
+
+  fd = g_open (context->filename, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, 0666);
+
+  if (fd != -1)
+    {
+      out = TIFFFdOpen (fd, context->filename, "w");
+
+      gimp_image_get_resolution (context->image_id, &xres, &yres);
+      width = gimp_image_width (context->image_id);
+      height = gimp_image_height (context->image_id);
+
+      TIFFSetField (out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_SEPARATED);
+      TIFFSetField (out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+      TIFFSetField (out, TIFFTAG_INKSET, INKSET_CMYK);
+      TIFFSetField (out, TIFFTAG_BITSPERSAMPLE, 8);
+
+      TIFFSetField (out, TIFFTAG_SAMPLESPERPIXEL, 4);
+
+      TIFFSetField (out, TIFFTAG_IMAGEWIDTH, width);
+      TIFFSetField (out, TIFFTAG_IMAGELENGTH, height);
+      TIFFSetField (out, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
+      TIFFSetField (out, TIFFTAG_XRESOLUTION, xres);
+      TIFFSetField (out, TIFFTAG_YRESOLUTION, yres);
+      TIFFSetField (out, TIFFTAG_ROWSPERSTRIP, STRIPHEIGHT);
+      TIFFSetField (out, TIFFTAG_COMPRESSION, context->compression_type);
+
+      if (context->settings.embed_profile && context->destination_profile_data)
+        {
+          TIFFSetField (out, TIFFTAG_ICCPROFILE,
+                        context->destination_profile_length,
+                        context->destination_profile_data);
+        }
+
+      write_tiff_data (out, context, width, height);
+
+      TIFFWriteDirectory (out);
+      TIFFClose (out);
+
+      return TRUE;
+    }
+  else
+    {
+      g_string_printf (context->message,
+                       _("Could not open '%s' for writing: %s"),
+                       gimp_filename_to_utf8 (context->filename), g_strerror (errno));
+    }
+
+  return FALSE;
+}
+
+
+static gboolean
+write_tiff_data (TIFF    *out,
+                 SeparateContext *context,
+                 gint32  width,
+                 gint32  height)
+{
+  gint32 BufSizeOut = TIFFStripSize (out);
+  guchar *bsrc, *bdest;
+  GeglBuffer *buffer_src;
+  gint32 i;
+  gint StripCount = (height + (STRIPHEIGHT - 1)) / STRIPHEIGHT;
+  const Babl *src_format = babl_format ("R'G'B' u8"), *dest_format = babl_format ("CMYK u8");
+  GimpColorTransform *transform;
+
+  transform =
+    gimp_color_transform_new (context->source_profile, src_format,
+                              context->destination_profile, dest_format,
+                              context->intent,
+                              context->bpc ? GIMP_COLOR_TRANSFORM_FLAGS_BLACK_POINT_COMPENSATION : 0);
+
+  if (! transform)
+    {
+      g_string_printf (context->message, _("Cannot setup color separation."));
+
+      return FALSE;
+   }
+
+  buffer_src = gimp_drawable_get_buffer (context->drawable_id);
+ 
+  if (! (bdest = (guchar *)_TIFFmalloc (BufSizeOut)) ||
+      ! (bsrc = g_try_malloc (width * STRIPHEIGHT * 3)))
+    {
+      g_string_printf (context->message, _("Cannot allocate working memory."));
+
+      g_object_unref (transform);
+
+      return FALSE;
+    }
+
+  gimp_progress_init (_("Exporting TIFF..."));
+
+  for (i = 0; i < StripCount; i++)
+    {
+      gint32 top, buffer_height;
+
+      gimp_progress_update (((double)i) / ((double)StripCount));
+
+      top = i * STRIPHEIGHT;
+      buffer_height = (top + STRIPHEIGHT > height) ? height - top : STRIPHEIGHT;
+      gegl_buffer_get (buffer_src, GEGL_RECTANGLE (0, top, width, buffer_height), 1.0, src_format, bsrc, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
+
+      gimp_color_transform_process_pixels (transform, src_format, bsrc, dest_format, bdest, width * buffer_height);
+
+      TIFFWriteEncodedStrip (out, i, bdest, BufSizeOut);
+    }
+
+  gimp_progress_update (1.0);
+
+  _TIFFfree (bdest);
+  g_free (bsrc);
+
+  g_object_unref (transform);
+
+  g_object_unref (buffer_src);
+
+  return TRUE;
+}
+
+/***** JPEG export functions *****/
+
+typedef struct _JpegWriteErrMgr
+{
+  struct jpeg_error_mgr jerr;
+  jmp_buf buf;
+} JpegWriteErrMgr;
+
+static void
+jpeg_write_error_handler (j_common_ptr cinfo)
+{
+  JpegWriteErrMgr *mgr = (JpegWriteErrMgr *) (cinfo->err);
+
+  longjmp (mgr->buf, 1);
+}
+
+#define MARKER_LENGTH 65533
+#define ICC_MARKER_HEADER_LENGTH 14
+#define ICC_MARKER_DATA_LENGTH (MARKER_LENGTH - ICC_MARKER_HEADER_LENGTH)
+
+static gboolean
+export_jpeg (SeparateContext *context)
+{
+  FILE *stream;
+
+  stream = g_fopen (context->filename, "wb");
+
+  if (stream)
+    {
+      gdouble xres, yres;
+      struct jpeg_compress_struct cinfo;
+      JpegWriteErrMgr mgr;
+
+      mgr.jerr.error_exit = jpeg_write_error_handler;
+      cinfo.err = jpeg_std_error (&mgr.jerr);
+      jpeg_create_compress (&cinfo);
+
+      if (setjmp (mgr.buf) != 0)
+        {
+          gimp_message (_("Failed to exporting JPEG."));
+          return FALSE;
+        }
+
+      jpeg_stdio_dest (&cinfo, stream);
+
+      cinfo.image_width = gimp_image_width (context->image_id);
+      cinfo.image_height = gimp_image_height (context->image_id);
+      cinfo.input_components = 4;
+      cinfo.in_color_space = JCS_CMYK;
+      cinfo.jpeg_color_space = JCS_CMYK;
+
+      jpeg_set_defaults (&cinfo);
+
+      jpeg_set_colorspace (&cinfo, JCS_CMYK);
+
+      jpeg_set_quality (&cinfo, context->settings.compression, TRUE);
+
+      gimp_image_get_resolution (context->image_id, &xres, &yres);
+      cinfo.X_density = xres;
+      cinfo.Y_density = yres;
+      cinfo.density_unit = 1;
+      cinfo.optimize_coding = TRUE;
+      cinfo.dct_method = JDCT_FLOAT;
+      cinfo.write_JFIF_header = TRUE;
+      cinfo.write_Adobe_marker = TRUE;
+
+      jpeg_start_compress (&cinfo, TRUE);
+
+      if (context->settings.embed_profile && context->destination_profile_data)
+        write_jpeg_profile_data (&cinfo,
+                                 context->destination_profile_data,
+                                 context->destination_profile_length);
+
+      write_jpeg_data (&cinfo, context);
+
+      jpeg_finish_compress (&cinfo);
+
+      jpeg_destroy_compress (&cinfo);
+      fclose (stream);
+
+      return TRUE;
+    }
+  else
+    {
+      g_string_printf (context->message,
+                       _("Could not open '%s' for writing: %s"),
+                       gimp_filename_to_utf8 (context->filename), g_strerror (errno));
+    }
+
+  return FALSE;
+}
+
+
+static void
+write_jpeg_profile_data (j_compress_ptr  cinfo,
+                         const gchar    *profile_data,
+                         gsize           profile_length)
+{
+  gint n_markers, current_marker;
+
+  n_markers = profile_length / ICC_MARKER_DATA_LENGTH;
+
+  if (profile_length % ICC_MARKER_DATA_LENGTH)
+    n_markers++;
+
+  current_marker = 1;
+
+  while (profile_length > 0)
+    {
+      guint length;
+
+      length = MIN (profile_length, ICC_MARKER_DATA_LENGTH);
+      profile_length -= length;
+
+      jpeg_write_m_header (cinfo, JPEG_APP0 + 2, length + ICC_MARKER_HEADER_LENGTH);
+
+      jpeg_write_m_byte (cinfo, 'I');
+      jpeg_write_m_byte (cinfo, 'C');
+      jpeg_write_m_byte (cinfo, 'C');
+      jpeg_write_m_byte (cinfo, '_');
+      jpeg_write_m_byte (cinfo, 'P');
+      jpeg_write_m_byte (cinfo, 'R');
+      jpeg_write_m_byte (cinfo, 'O');
+      jpeg_write_m_byte (cinfo, 'F');
+      jpeg_write_m_byte (cinfo, 'I');
+      jpeg_write_m_byte (cinfo, 'L');
+      jpeg_write_m_byte (cinfo, 'E');
+      jpeg_write_m_byte (cinfo, 0);
+
+      jpeg_write_m_byte (cinfo, current_marker);
+      jpeg_write_m_byte (cinfo, n_markers);
+
+      while (length--)
+        {
+          jpeg_write_m_byte (cinfo, *profile_data);
+          profile_data++;
+        }
+
+      current_marker++;
+    }
+}
+
+static gboolean
+write_jpeg_data (j_compress_ptr   cinfo,
+                 SeparateContext *context)
+{
+  gint i;
+  guchar *src, *dest, *scanlines[64];
+  GeglBuffer *buffer_src;
+  cmsHTRANSFORM transform;
+
+  transform =
+    cmsCreateTransform (gimp_color_profile_get_lcms_profile (context->source_profile), TYPE_RGB_8,
+                        gimp_color_profile_get_lcms_profile (context->destination_profile), TYPE_CMYK_8 | FLAVOR_SH (1),
+                        context->intent,
+                        context->bpc ? cmsFLAGS_BLACKPOINTCOMPENSATION : 0);
+
+  if (! transform)
+    {
+      g_string_printf (context->message, _("Cannot setup color separation."));
+      return FALSE;
+    }
+
+  if (! (src  = g_try_malloc (cinfo->image_width * 3 * 64)) ||
+      ! (dest = g_try_malloc (cinfo->image_width * 4 * 64)))
+    {
+      g_string_printf (context->message, _("Cannot allocate working memory."));
+
+      g_free (src);
+      cmsDeleteTransform (transform);
+
+      return FALSE;
+    }
+
+  buffer_src = gimp_drawable_get_buffer (context->drawable_id);
+
+  gimp_progress_init (_("Exporting JPEG..."));
+
+  for (i = 0; i < 64; i++)
+    scanlines[i] = dest + i * cinfo->image_width * 4;
+
+  for (i = 0; i < cinfo->image_height; i += 64)
+    {
+      gint n_lines;
+
+      n_lines = MIN (cinfo->image_height - i, 64);
+
+      gimp_progress_update ((gdouble)i / (gdouble)cinfo->image_height);
+
+      gegl_buffer_get (buffer_src, GEGL_RECTANGLE (0, i, cinfo->image_width, n_lines), 1.0, babl_format ("R'G'B' u8"), src, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
+
+      cmsDoTransform (transform, src, dest, cinfo->image_width * n_lines);
+
+      jpeg_write_scanlines (cinfo, (JSAMPARRAY)scanlines, n_lines);
+    }
+
+  gimp_progress_update (1.0);
+
+  g_free (src);
+  g_free (dest);
+
+  cmsDeleteTransform (transform);
+  
+  g_object_unref (buffer_src);
+
+  return TRUE;
+}
+
+/***** PSD export functions *****/
+
+typedef struct _PSDHeader
+{
+  guint32 signature; /* '8BPS' */
+  guint16 version;   /* always 1 */
+  gchar reserved[6];
+  gint16 channels;
+  gint32 height; /* npixels */
+  gint32 width;
+  gint16 depth;
+  gint16 mode;
+} __attribute__ ((packed)) PSDHeader;
+
+typedef struct _PSDResResource
+{
+  guint32 type; /* '8BIM' */
+  guint16 id;   /* 0x03ed */
+  gchar name[2]; /* "\0\0" */
+  gint32 size;
+  gint32 hres;
+  gint16 hres_unit;
+  gint16 width_unit;
+  gint32 vres;
+  gint16 vres_unit;
+  gint16 height_unit;
+} __attribute__ ((packed)) PSDResResource;
+
+typedef struct _PSDIccResource
+{
+  guint32 type; /* '8BIM' */
+  guint16 id;   /* 0x040f */
+  gchar name[2]; /* "\0\0" */
+  gint32 size;
+} __attribute__ ((packed)) PSDIccResource;
+
+
+#define PSD_MAX_BUFFER_SIZE 1048576
+
+
+gboolean
+export_psd (SeparateContext *context)
+{
+  int fd;
+  PSDHeader header;
+  PSDResResource res;
+  PSDIccResource icc;
+  gboolean result = FALSE;
+
+  fd = g_open (context->filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 00644);
+
+  if (fd != -1)
+    {
+      gint32 length;
+      gint32 width, height;
+      gdouble xres, yres;
+      off_t count;
+
+      width = gimp_image_width (context->image_id);
+      height = gimp_image_height (context->image_id);
+
+      /* header */
+      header.signature = GUINT32_TO_BE (0x38425053);
+      header.version = GUINT16_TO_BE (1);
+      memset (header.reserved, 0, sizeof (header.reserved));
+      header.channels = GINT16_TO_BE (4); /* C, M, Y, K, and no alpha channels */
+      header.height = GINT32_TO_BE (height);
+      header.width = GINT32_TO_BE (width);
+      header.depth = GINT16_TO_BE (8); /* 8bit per channels */
+      header.mode = GINT16_TO_BE (4); /* CMYK Mode */
+
+      count = write (fd, &header, sizeof (header));
+
+      /***** color mode data *****/
+      length = 0;
+      count = write (fd, &length, sizeof (gint32));
+
+      /***** image resources *****/
+      length = 0;
+
+      /* resolution info */
+      gimp_image_get_resolution (context->image_id, &xres, &yres);
+      res.type = GUINT32_TO_BE (0x3842494d);
+      res.id = GUINT16_TO_BE (0x03ed);
+      memset (res.name, 0, 2);
+      res.size = GINT32_TO_BE (16);
+      res.hres = GINT32_TO_BE (xres * 65536.0);
+      res.hres_unit = GINT16_TO_BE (1);
+      res.width_unit = GINT16_TO_BE (1);
+      res.vres = GINT32_TO_BE (yres * 65536.0);
+      res.vres_unit = GINT16_TO_BE (1);
+      res.height_unit = GINT16_TO_BE (1);
+
+      length += sizeof (PSDResResource);
+
+      /* ICC profile */
+      if (context->settings.embed_profile &&
+          context->destination_profile_data)
+        {
+          icc.type = res.type;
+          icc.id = GUINT16_TO_BE (0x040f);
+          memset (icc.name, 0, 2);
+          icc.size = GINT32_TO_BE (context->destination_profile_length);
+
+          length += sizeof (PSDIccResource) + context->destination_profile_length;
+        }
+
+      /* write data... */
+      length = GINT32_TO_BE (length);
+      count = write (fd, &length, sizeof (gint32));
+
+      count = write (fd, &res, sizeof (PSDResResource));
+
+      if (context->settings.embed_profile &&
+          context->destination_profile_data)
+        {
+          count = write (fd, &icc, sizeof (PSDIccResource));
+          count = write (fd, context->destination_profile_data,
+                         context->destination_profile_length);
+        }
+
+      /***** layer and mask info *****/
+      length = 0;
+      count = write (fd, &length, sizeof (gint32));
+
+      /***** image data *****/
+      result = context->settings.compression ?
+               write_psd_data_packbits (fd, context) :
+               write_psd_data_raw (fd, context);
+
+      close (fd);
+    }
+  else
+    {
+      g_string_printf (context->message,
+                       _("Could not open '%s' for writing: %s"),
+                       gimp_filename_to_utf8 (context->filename), g_strerror (errno));
+    }
+
+  return result;
+}
+
+static gboolean
+write_psd_data_packbits (int               fd,
+                         SeparateContext  *context)
+{
+  gint i, x, y, col;
+  gint32 current, total;
+  gint32 width = context->width;
+  gint32 height = context->height;
+  off_t data_head, data_end, result;
+  gint16 compression;
+  GeglBuffer *buffer_src;
+  guchar *src, *dest;
+  guint16 line_bytes[PSD_MAX_PIXELS];
+  gint buf_width, buf_height;
+  cmsHTRANSFORM transform;
+  gchar channel_name[4][2] = { "C", "M", "Y", "K" };
+
+  /* FLAVOR_SH (1) has no effects when PLANER_SH (1) is enabled */
+  transform =
+    cmsCreateTransform (gimp_color_profile_get_lcms_profile (context->source_profile), TYPE_RGB_8,
+                        gimp_color_profile_get_lcms_profile (context->destination_profile), TYPE_CMYK_8_PLANAR,
+                        context->intent,
+                        context->bpc ? cmsFLAGS_BLACKPOINTCOMPENSATION : 0);
+
+  if (! transform)
+    {
+      g_string_printf (context->message, _("Cannot setup color separation."));
+      return FALSE;
+    }
+
+  current = 0;
+  total = height * 4;
+
+  buf_width = ceil (width * 1.334);
+  buf_height = MIN (PSD_MAX_BUFFER_SIZE / (buf_width * 7), height);
+  buf_height = MAX (buf_height, 64);
+
+  if (! (src  = g_try_malloc (buf_width * buf_height * 4)) ||
+      ! (dest = g_try_malloc (buf_width * buf_height * 3)))
+    {
+      g_string_printf (context->message, _("Cannot allocate working memory."));
+
+      g_free (src);
+      cmsDeleteTransform (transform);
+
+      return FALSE;
+    }
+
+  buffer_src = gimp_drawable_get_buffer (context->drawable_id);
+
+  gimp_progress_init ("");
+
+  compression = GINT16_TO_BE (1);
+  result = write (fd, &compression, sizeof (gint16));
+
+  data_head = lseek (fd, 0, SEEK_CUR);   /* head of byte counts */
+  data_end = data_head + height * 4 * 2; /* head of pixel data */
+
+  for (i = 0; i < 4; i++)
+    {
+      gimp_progress_set_text_printf (_("Exporting Photoshop PSD (%s channel)..."),
+                                     channel_name[i]);
+
+      for (y = 0; y < height; y += buf_height, current += buf_height)
+        {
+          gint n_lines = MIN (height - y, buf_height);
+          guchar *_src = src + i * width * n_lines;
+          guchar *_dest = dest;
+          gint read_bytes = 0;
+          gint write_bytes = 0;
+
+          gimp_progress_update ((gdouble)current / (gdouble)total);
+
+          gegl_buffer_get (buffer_src, GEGL_RECTANGLE (0, y, width, n_lines), 1.0, babl_format ("R'G'B' u8"), dest, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
+
+          cmsDoTransform (transform, dest, src, width * n_lines);
+
+          for (col = 0; col < n_lines; col++)
+            {
+              gint _write_bytes = write_bytes;
+              gchar *count = (gchar *)(_dest + write_bytes++);
+
+              *count = 0;
+
+              _dest[write_bytes++] = 0xff - _src[read_bytes++];
+
+              for (x = 1; x < width; x++)
+                {
+                  gchar tmp = 0xff - _src[read_bytes++];
+
+                  if (_dest[write_bytes - 1] == tmp)
+                    {
+                      if (*count == -127)
+                        {
+                          count = (gchar *)(_dest + write_bytes++);
+                          *count = 0;
+                          _dest[write_bytes++] = tmp;
+                        }
+                      else if (*count <= 0)
+                        {
+                          (*count)--;
+                        }
+                      else
+                        {
+                          (*count)--;
+                          count = (gchar *)(_dest + write_bytes - 1);
+                          *count = -1;
+                          _dest[write_bytes++] = tmp;
+                        }
+                    }
+                  else
+                    {
+                      if (*count >= 0 && *count != 127)
+                        {
+                          (*count)++;
+                          _dest[write_bytes++] = tmp;
+                        }
+                      else
+                        {
+                          count = (gchar *)(_dest + write_bytes++);
+                          *count = 0;
+                          _dest[write_bytes++] = tmp;
+                        }
+                    }
+                }
+              line_bytes[y + col] = GINT16_TO_BE (write_bytes - _write_bytes);
+            }
+
+          /* seek to end of pixel data */
+          lseek (fd, data_end, SEEK_SET);
+          result = write (fd, _dest, write_bytes);
+          data_end += write_bytes;
+        }
+
+      /* seek to bytes per line data */
+      lseek (fd, data_head + (height * i) * 2, SEEK_SET);
+      result = write (fd, line_bytes, height * 2);
+    }
+
+  gimp_progress_update (1.0);
+
+  g_free (src);
+  g_free (dest);
+
+  cmsDeleteTransform (transform);
+
+  g_object_unref (buffer_src);
+
+  return TRUE;
+}
+
+
+static gboolean
+write_psd_data_raw (int               fd,
+                    SeparateContext  *context)
+{
+  gint i, y;
+  gint32 width = context->width;
+  gint32 height = context->height;
+  off_t data_head, result;
+  gint16 compression;
+  GeglBuffer *buffer_src;
+  guchar *src, *dest;
+  gint buf_height;
+  cmsHTRANSFORM transform;
+
+  /* FLAVOR_SH (1) has no effects when PLANER_SH (1) is enabled */
+  transform =
+    cmsCreateTransform (gimp_color_profile_get_lcms_profile (context->source_profile), TYPE_RGB_8,
+                        gimp_color_profile_get_lcms_profile (context->destination_profile), TYPE_CMYK_8_PLANAR,
+                        context->intent,
+                        context->bpc ? cmsFLAGS_BLACKPOINTCOMPENSATION : 0);
+
+  if (! transform)
+    {
+      g_string_printf (context->message, _("Cannot setup color separation."));
+      return FALSE;
+    }
+
+  buf_height = MIN (PSD_MAX_BUFFER_SIZE / (width * 7), height);
+  buf_height = MAX (buf_height, 64);
+
+  if (! (src  = g_try_malloc (width * buf_height * 3)) ||
+      ! (dest = g_try_malloc (width * buf_height * 4)))
+    {
+      g_string_printf (context->message, _("Cannot allocate working memory."));
+
+      g_free (src);
+      cmsDeleteTransform (transform);
+
+      return FALSE;
+    }
+
+  buffer_src = gimp_drawable_get_buffer (context->drawable_id);
+
+  gimp_progress_init (_("Exporting Photoshop PSD..."));
+
+  compression = 0;
+  result = write (fd, &compression, sizeof (gint16));
+
+  data_head = lseek (fd, 0, SEEK_CUR);
+
+  for (y = 0; y < height; y += buf_height)
+    {
+      gint n_lines;
+      guint32 *tmp = (guint32 *)dest;
+
+      gimp_progress_update (y / height);
+
+      n_lines = MIN (height - y, buf_height);
+      //gimp_pixel_rgn_get_rect (&region, src, 0, y, width, n_lines);
+      gegl_buffer_get (buffer_src, GEGL_RECTANGLE (0, y, width, n_lines), 1.0, babl_format ("R'G'B' u8"), src, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
+
+      cmsDoTransform (transform, src, dest, width * n_lines);
+
+      for (i = 0; i < width * n_lines; i++)
+        {
+          *tmp = 0xffffffff - *tmp;
+          tmp++;
+        }
+
+      for (i = 0; i < 4; i++)
+        {
+          lseek (fd, data_head + (i * height + y) * width, SEEK_SET);
+          result = write (fd, dest + i * width * n_lines, width * n_lines);
+        }
+    }
+
+  gimp_progress_update (1.0);
+
+  g_free (src);
+  g_free (dest);
+
+  cmsDeleteTransform (transform);
+
+  g_object_unref (buffer_src);
+
+  return TRUE;
+}
diff --git a/plug-ins/common/gimprc.common b/plug-ins/common/gimprc.common
index 0ff328d..65ad792 100644
--- a/plug-ins/common/gimprc.common
+++ b/plug-ins/common/gimprc.common
@@ -25,6 +25,7 @@ edge_neon_RC = edge-neon.rc.o
 emboss_RC = emboss.rc.o
 file_aa_RC = file-aa.rc.o
 file_cel_RC = file-cel.rc.o
+file_cmyk_save_RC = file-cmyk-save.rc.o
 file_compressor_RC = file-compressor.rc.o
 file_csource_RC = file-csource.rc.o
 file_desktop_link_RC = file-desktop-link.rc.o
diff --git a/plug-ins/common/plugin-defs.pl b/plug-ins/common/plugin-defs.pl
index 8ec6073..0cc6a07 100644
--- a/plug-ins/common/plugin-defs.pl
+++ b/plug-ins/common/plugin-defs.pl
@@ -26,6 +26,7 @@
     'emboss' => { ui => 1 },
     'file-aa' => { ui => 1, gegl => 1, optional => 1, libs => 'AA_LIBS' },
     'file-cel' => { ui => 1, gegl => 1 },
+    'file-cmyk-save' => { ui => 1, optional => 1, libs => 'FILE_CMYK_LIBS', cflags => 'FILE_CMYK_CFLAGS' },
     'file-csource' => { ui => 1, gegl => 1 },
     'file-compressor' => { gio => 1, libdep => 'Z:BZIP2:LZMA', cflags => 'LZMA_CFLAGS' },
     'file-desktop-link' => {},
