////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// Implementation file
//
// SPDX-FileCopyrightText: © 2012, IOhannes m zmölnig and the GEM contributors
// SPDX-License-Identifier: GPL-2.0-or-later
//
////////////////////////////////////////////////////////

/* this implements ImageMagick loading/saving using Magick++ */

#include "imageMAGICK.h"
#include "Gem/RTE.h"

#include <Magick++.h>

using namespace gem::plugins;

namespace MagickCore {};
using namespace MagickCore;

namespace MagickLib  {};
using namespace MagickLib;

/////////////////////////////////////////////////////////
// really open the file ! (OS dependent)
//
/////////////////////////////////////////////////////////
bool imageMAGICK :: load(std::string filename, imageStruct&result,
                         gem::Properties&props)
{
  Magick::Image image;
  try {
    // Read a file into image object
    try {
      image.read( filename );
      image.autoOrient();
    } catch (Magick::Warning&e) {
      fprintf(stderr, "[GEM:imageMAGICK] loading problem: %s\n", e.what());
    }

    result.xsize=static_cast<int>(image.columns());
    result.ysize=static_cast<int>(image.rows());
    result.setFormat(GEM_RGBA);
    result.reallocate();

    result.upsidedown=true;

    try {
      image.write(0,0,result.xsize,result.ysize,
#ifdef __APPLE__
                  "ARGB",
#else
                  "RGBA",
#endif
                  Magick::CharPixel,
                  reinterpret_cast<void*>(result.data));
    } catch (Magick::Warning&e) {
      fprintf(stderr, "[GEM:imageMAGICK] decoding problem: %s\n", e.what());
    }
  } catch (Magick::Exception&e)  {
    fprintf(stderr, "[GEM:imageMAGICK] loading image failed with: %s\n", e.what());
    return false;
  }
  return true;
}
bool imageMAGICK::save(const imageStruct&image, const std::string&filename,
                       const std::string&mimetype, const gem::Properties&props)
{
  const imageStruct*img=const_cast<imageStruct*>(&image);
  const imageStruct*cImage=img;
  imageStruct pImage;

  std::string cs;
  switch(img->format) {
  case GEM_RAW_GRAY:
    cs="K";
    /* for whatever reasons, we need to invert the greyscale colors... */
    img->copy2Image(&pImage);
    do {
      unsigned char*data = pImage.data;
      for(int row=0; row<pImage.ysize; row++) {
        for(int col=0; col<pImage.xsize; col++) {
          *data = 255 - *data;
          data++;
        }
      }
    } while(0);
    cImage = &pImage;
    break;
  case GEM_RAW_RGBA:
#ifdef __APPLE__
    cs="ABGR";
#else
    cs="RGBA";
#endif
    break;
  /* coverity[unterminated_default] */
  default:
    pImage.convertFrom(img, GEM_RAW_RGB);
    cImage = &pImage;
  case GEM_RAW_RGB:
    cs="RGB";
    break;
  case GEM_RAW_BGRA:
#ifdef __APPLE__
    cs="ARGB";
#else
    cs="BGRA";
#endif
    break;
  }
  try {
    Magick::Image mimage(cImage->xsize, cImage->ysize, cs, Magick::CharPixel,
                         cImage->data);
    // since openGL is upside down
    if(!cImage->upsidedown) {
      mimage.flip();
    }
    if(GEM_RAW_GRAY == img->format)
      mimage.colorSpace(Magick::GRAYColorspace);

    // 8 bits per channel are enough!
    // LATER make this dependent on the image->type
    mimage.depth(8);
    double quality;
    if(props.get("quality", quality)) {
      mimage.quality(quality);
    }

    try {
      // finally convert and export
      mimage.write(filename);
    } catch (Magick::Warning&e) {
      fprintf(stderr, "[GEM:imageMAGICK] saving problem: %s\n", e.what());
    }

  } catch (Magick::Exception&e) {
    fprintf(stderr, "[GEM:imageMAGICK] %s\n", e.what());
    return false;
  } catch (...) {
    fprintf(stderr, "[GEM:imageMAGICK] uncaught exception!\n");
    return false;
  }
  return true;
}
