(********************************************************************)
(*                                                                  *)
(*  imagefile.s7i  Support for various image file formats.          *)
(*  Copyright (C) 2021, 2022  Thomas Mertes                         *)
(*                                                                  *)
(*  This file is part of the Seed7 Runtime Library.                 *)
(*                                                                  *)
(*  The Seed7 Runtime Library is free software; you can             *)
(*  redistribute it and/or modify it under the terms of the GNU     *)
(*  Lesser General Public License as published by the Free Software *)
(*  Foundation; either version 2.1 of the License, or (at your      *)
(*  option) any later version.                                      *)
(*                                                                  *)
(*  The Seed7 Runtime Library 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 Lesser General Public License for more    *)
(*  details.                                                        *)
(*                                                                  *)
(*  You should have received a copy of the GNU Lesser 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.                       *)
(*                                                                  *)
(********************************************************************)


  include "png.s7i";
  include "gif.s7i";
  include "jpeg.s7i";
  include "bmp.s7i";
  include "ico.s7i";
  include "pbm.s7i";
  include "pgm.s7i";
  include "ppm.s7i";
  include "tiff.s7i";


(**
 *  Determine if ''fileName'' uses an image extension.
 *  Image extensions are .png, .gif, .jpeg, .jpg, .pbm, .pgm, .ppm,
 *  .bpm, .ico .tiff and .tif.
 *  @param imageFileName Name of the image file.
 *  @return TRUE if ''fileName'' ends with an image extension,
 *          FALSE otherwise.
 *)
const func boolean: hasImageExtension (in var string: fileName) is func
  result
    var boolean: hasImageExtension is FALSE;
  begin
    fileName := lower(fileName);
    hasImageExtension := endsWith(fileName, ".png") or
                         endsWith(fileName, ".gif") or
                         endsWith(fileName, ".jpeg") or
                         endsWith(fileName, ".jpg") or
                         endsWith(fileName, ".pbm") or
                         endsWith(fileName, ".pgm") or
                         endsWith(fileName, ".ppm") or
                         endsWith(fileName, ".bmp") or
                         endsWith(fileName, ".ico") or
                         endsWith(fileName, ".tiff") or
                         endsWith(fileName, ".tif");
  end func;


(**
 *  Reads an image file into a pixmap.
 *  [[bmp|BMP]], [[gif|GIF]], [[ico|ICO]], [[jpeg|JPEG]], [[png|PNG]],
 *  [[pbm|PBM]], [[pgm|PGM]], [[ppm|PPM]] and [[tiff|TIFF]] images are supported.
 *  The file is checked for magic numbers and the corresponding read
 *  function is used, to read the actual image.
 *  @param imageFile File that contains an image.
 *  @return A pixmap with the image, or
 *          PRIMITIVE_WINDOW.value if the file is not in a valid
 *          image file format.
 *)
const func PRIMITIVE_WINDOW: readImage (inout file: imageFile) is func
  result
    var PRIMITIVE_WINDOW: pixmap is PRIMITIVE_WINDOW.value;
  local
    var string: magic is "";
  begin
    block
      magic := gets(imageFile, length(BMP_MAGIC));
      if magic = BMP_MAGIC then
        seek(imageFile, 1);
        pixmap := readBmp(imageFile);
      elsif magic = PBM_ASCII_MAGIC or magic = PBM_BINARY_MAGIC then
        seek(imageFile, 1);
        pixmap := readPbm(imageFile);
      elsif magic = PGM_ASCII_MAGIC or magic = PGM_BINARY_MAGIC then
        seek(imageFile, 1);
        pixmap := readPgm(imageFile);
      elsif magic = PPM_ASCII_MAGIC or magic = PPM_BINARY_MAGIC then
        seek(imageFile, 1);
        pixmap := readPpm(imageFile);
      else
        magic &:= gets(imageFile, length(JPEG_MAGIC) - length(BMP_MAGIC));
        if magic = JPEG_MAGIC then
          seek(imageFile, 1);
          pixmap := readJpeg(imageFile);
        else
          magic &:= gets(imageFile, length(ICO_MAGIC) - length(JPEG_MAGIC));
          if magic = ICO_MAGIC then
            seek(imageFile, 1);
            pixmap := readIco(imageFile);
          elsif magic = TIFF_MAGIC_LE or magic = TIFF_MAGIC_BE then
            seek(imageFile, 1);
            pixmap := readTiff(imageFile);
          else
            magic &:= gets(imageFile, length(GIF_MAGIC_87) - length(ICO_MAGIC));
            if magic = GIF_MAGIC_87 or magic = GIF_MAGIC_89 then
              seek(imageFile, 1);
              pixmap := readGif(imageFile);
            else
              magic &:= gets(imageFile, length(PNG_MAGIC) - length(GIF_MAGIC_87));
              if magic = PNG_MAGIC then
                seek(imageFile, 1);
                pixmap := readPng(imageFile);
              end if;
            end if;
          end if;
        end if;
      end if;
    exception
      otherwise: noop;
    end block;
  end func;


(**
 *  Reads an image file with the given ''imageFileName'' into a pixmap.
 *  [[bmp|BMP]], [[gif|GIF]], [[ico|ICO]], [[jpeg|JPEG]], [[png|PNG]],
 *  [[pbm|PBM]], [[pgm|PGM]], [[ppm|PPM]] and [[tiff|TIFF]] images are supported.
 *  The file is checked for magic numbers and the corresponding read
 *  function is used, to read the actual image. The file extension of
 *  ''imageFileName'' is not used to decide about the image file type.
 *  @param imageFileName Name of the image file.
 *  @return A pixmap with the image, or
 *          PRIMITIVE_WINDOW.value if the file cannot be opened or
 *          is not in a valid image file format.
 *)
const func PRIMITIVE_WINDOW: readImage (in string: imageFileName) is func
  result
    var PRIMITIVE_WINDOW: pixmap is PRIMITIVE_WINDOW.value;
  local
    var file: imageFile is STD_NULL;
   begin
    imageFile := open(imageFileName, "r");
    if imageFile <> STD_NULL then
      pixmap := readImage(imageFile);
      close(imageFile);
    end if;
  end func;