diff --git a/src/Makefile b/src/Makefile
index fe2b9cfd..7559d1f3 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -809,7 +809,7 @@ OBJS = main.o init.o graph.o $(APIOBJ) misc.o special.o \
        windows.o brush.o realpath.o mountlist.o input.o hotkeys.o \
        transform.o pversion.o factory.o $(PLATFORMOBJ) \
        loadsave.o loadsavefuncs.o \
-       pngformat.o motoformats.o stformats.o c64formats.o \
+       pngformat.o motoformats.o stformats.o c64formats.o cpcformats.o \
        fileformats.o miscfileformats.o libraw2crtc.o \
        brush_ops.o buttons_effects.o layers.o \
        oldies.o tiles.o colorred.o unicode.o gfx2surface.o \
@@ -821,7 +821,7 @@ endif
 TESTSOBJS = $(patsubst %.c,%.o,$(wildcard tests/*.c)) \
             miscfileformats.o fileformats.o oldies.o libraw2crtc.o \
             loadsavefuncs.o packbits.o tifformat.o c64load.o 6502.o \
-            pngformat.o motoformats.o stformats.o c64formats.o \
+            pngformat.o motoformats.o stformats.o c64formats.o cpcformats.o \
             op_c.o colorred.o \
             unicode.o \
             io.o realpath.o version.o pversion.o \
diff --git a/src/cpcformats.c b/src/cpcformats.c
new file mode 100644
index 00000000..55027808
--- /dev/null
+++ b/src/cpcformats.c
@@ -0,0 +1,1476 @@
+/* vim:expandtab:ts=2 sw=2:
+*/
+/*  Grafx2 - The Ultimate 256-color bitmap paint program
+
+    Copyright 2018-2019 Thomas Bernard
+    Copyright 2011 Pawel Góralski
+    Copyright 2009 Petter Lindquist
+    Copyright 2008 Yves Rizoud
+    Copyright 2008 Franck Charlet
+    Copyright 2007-2011 Adrien Destugues
+    Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud)
+
+    Grafx2 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; version 2
+    of the License.
+
+    Grafx2 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 Grafx2; if not, see 
+*/
+
+///@file cpcformats.c
+/// Formats for the Amstrad CPC / CPC Plus computers
+
+#include 
+#include 
+#include "global.h"
+#include "fileformats.h"
+#include "io.h"
+#include "loadsavefuncs.h"
+#include "libraw2crtc.h"
+#include "oldies.h"
+#include "gfx2mem.h"
+#include "gfx2log.h"
+
+/**
+ * Test for SCR file (Amstrad CPC)
+ *
+ * SCR file format is from "Advanced OCP Art Studio" :
+ * http://www.cpcwiki.eu/index.php/Format:Advanced_OCP_Art_Studio_File_Formats
+ *
+ * .WIN "window" format is also supported.
+ *
+ * For now we check the presence of a valid PAL file.
+ * If the PAL file is not there the pixel data may still be valid.
+ * The file size depends on the screen resolution.
+ * An AMSDOS header would be a good indication but in some cases it may not
+ * be there.
+ */
+void Test_SCR(T_IO_Context * context, FILE * file)
+{
+  // http://orgams.wikidot.com/le-format-impdraw-v2
+  // http://orgams.wikidot.com/les-fichiers-win-compatibles-ocp-art-studio
+  FILE * pal_file;
+  unsigned long pal_size, file_size;
+  byte mode, color_anim_flag;
+  word loading_address = 0;
+
+  File_error = 1;
+
+  if (CPC_check_AMSDOS(file, &loading_address, &file_size))
+  {
+    if (loading_address == 0x170) // iMPdraw v2
+    {
+      byte buffer[0x90];
+      fseek(file, 128, SEEK_SET); // right after AMSDOS header
+      Read_bytes(file, buffer, 0x90);
+      GFX2_LogHexDump(GFX2_DEBUG, "", buffer, 0, 0x90);
+      File_error = 0;
+      return;
+    }
+    else if ((loading_address == 0x200 || loading_address == 0xc000) && file_size > 16000)
+    {
+      File_error = 0;
+      return;
+    }
+  }
+  else
+    file_size = File_length_file(file);
+
+  if (file_size > 16384*2)
+    return;
+
+  // requires the PAL file
+  pal_file = Open_file_read_with_alternate_ext(context, "pal");
+  if (pal_file == NULL)
+    return;
+  /** @todo the palette data can be hidden in the 48 "empty" bytes
+   * every 2048 bytes of a standard resolution SCR file.
+   * So we should detect the hidden Z80 code and load them.
+   * Load address of file is C000. Z80 code :
+   * C7D0: 3a d0 d7 cd 1c bd 21 d1 d7 46 48 cd 38 bc af 21 | :.....!..FH.8..!
+   * C7E0: d1 d7 46 48 f5 e5 cd 32 bc e1 f1 23 3c fe 10 20 | ..FH...2...#<.. 
+   * C7F0: f1 c3 18 bb 00 00 00 00 00 00 00 00 00 00 00 00 | ................
+   * mode and palette :
+   * D7D0: 00 1a 00 0c 03 0b 01 0d 17 10 02 0f 09 19 06 00 | ................
+   * https://gitlab.com/GrafX2/grafX2/merge_requests/121#note_119964168
+   */
+
+
+  if (CPC_check_AMSDOS(pal_file, NULL, &pal_size))
+    fseek(pal_file, 128, SEEK_SET); // right after AMSDOS header
+  else
+  {
+    pal_size = File_length_file(pal_file);
+    fseek(pal_file, 0, SEEK_SET);
+  }
+
+  if (pal_size != 239)
+  {
+    fclose(pal_file);
+    return;
+  }
+
+  if (!Read_byte(pal_file, &mode) || !Read_byte(pal_file, &color_anim_flag))
+  {
+    fclose(pal_file);
+    return;
+  }
+  GFX2_Log(GFX2_DEBUG, "Test_SCR() mode=%d color animation flag %02X\n", mode, color_anim_flag);
+  if (mode <= 2 && (color_anim_flag == 0 || color_anim_flag == 0xff))
+    File_error = 0;
+  fclose(pal_file);
+}
+
+/**
+ * Load Advanced OCP Art Studio files (Amstrad CPC)
+ *
+ * Only standard resolution files (Mode 0 160x200, mode 1 320x200 and
+ * mode 2 640x200) are supported. The .PAL file presence is required.
+ * "MJH" RLE packing is supported.
+ *
+ * .WIN "window" format is also supported.
+ *
+ * @todo Ask user for screen size (or register values) in order to support
+ * non standard resolutions.
+ */
+void Load_SCR(T_IO_Context * context)
+{
+    // The Amstrad CPC screen memory is mapped in a weird mode, somewhere
+    // between bitmap and textmode. Basically the only way to decode this is to
+    // emulate the video chip and read the bytes as needed...
+    // Moreover, the hardware allows the screen to have any size from 8x1 to
+    // 800x273 pixels, and there is no indication of that in the file besides
+    // its size. It can also use any of the 3 screen modes. Fortunately this
+    // last bit of information is stored in the palette file.
+    // Oh, and BTW, the picture can be offset, and it's even usual to do it,
+    // because letting 128 pixels unused at the beginning of the file make it a
+    // lot easier to handle screens using more than 16K of VRam.
+    // The pixel encoding change with the video mode so we have to know that
+    // before attempting to load anything...
+    // As if this wasn't enough, Advanced OCP Art Studio, the reference tool on
+    // Amstrad, can use RLE packing when saving files, meaning we also have to
+    // handle that.
+
+    // All this mess enforces us to load (and unpack if needed) the file to a
+    // temporary 32k buffer before actually decoding it.
+  FILE * pal_file, * file;
+  unsigned long real_file_size, file_size, amsdos_file_size = 0;
+  word addr;
+  word load_address = 0x4000; // default for OCP Art studio
+  word display_start = 0x4000;
+  byte mode, color_anim_flag, color_anim_delay;
+  byte pal_data[236]; // 12 palettes of 16+1 colors + 16 excluded inks + 16 protected inks
+  word width, height = 200;
+  byte bpp;
+  enum PIXEL_RATIO ratio;
+  byte * cpc_ram;
+  word x, y;
+  int i;
+  byte sig[3];
+  word block_length;
+  word win_width, win_height;
+  int is_win = 0;
+  int columns = 80;
+  int cpc_plus = 0;
+  const byte * cpc_plus_pal = NULL;
+
+  File_error = 1;
+  // requires the PAL file for OCP Art studio files
+  pal_file = Open_file_read_with_alternate_ext(context, "pal");
+  if (pal_file != NULL)
+  {
+    file_size = File_length_file(pal_file);
+    if (CPC_check_AMSDOS(pal_file, NULL, &file_size))
+      fseek(pal_file, 128, SEEK_SET); // right after AMSDOS header
+    else
+      fseek(pal_file, 0, SEEK_SET);
+    if (!Read_byte(pal_file, &mode) || !Read_byte(pal_file, &color_anim_flag)
+          || !Read_byte(pal_file, &color_anim_delay) || !Read_bytes(pal_file, pal_data, 236))
+    {
+      GFX2_Log(GFX2_WARNING, "Load_SCR() failed to load .PAL file\n");
+      fclose(pal_file);
+      return;
+    }
+    fclose(pal_file);
+    GFX2_Log(GFX2_DEBUG, "Load_SCR() mode=%d color animation flag=%02X delay=%u\n",
+             mode, color_anim_flag, color_anim_delay);
+  }
+
+  file = Open_file_read(context);
+  if (file == NULL)
+    return;
+  file_size = File_length_file(file);
+  real_file_size = file_size;
+  if (CPC_check_AMSDOS(file, &load_address, &amsdos_file_size))
+  {
+    display_start = load_address;
+    if (file_size < (amsdos_file_size + 128))
+    {
+      GFX2_Log(GFX2_ERROR, "Load_SCR() mismatch in file size. AMSDOS file size %lu, should be %lu\n", amsdos_file_size, file_size - 128);
+      fclose(file);
+      return;
+    }
+    else if (file_size > (amsdos_file_size + 128))
+      GFX2_Log(GFX2_INFO, "Load_SCR() %lu extra bytes at end of file\n", file_size - 128 - amsdos_file_size);
+    fseek(file, 128, SEEK_SET); // right after AMSDOS header
+    file_size = amsdos_file_size;
+  }
+  else
+    fseek(file, 0, SEEK_SET);
+
+  if (!Read_bytes(file, sig, 3) || !Read_word_le(file, &block_length))
+  {
+    fclose(file);
+    return;
+  }
+  fseek(file, -5, SEEK_CUR);
+
+  cpc_ram = GFX2_malloc(64*1024);
+  memset(cpc_ram, 0, 64*1024);
+
+  if (0 != memcmp(sig, "MJH", 3) || block_length > 16384)
+  {
+    // raw data
+    Read_bytes(file, cpc_ram + load_address, file_size);
+    i = file_size;
+  }
+  else
+  {
+    // MJH packed format
+    i = 0;
+    do
+    {
+      if (!Read_bytes(file, sig, 3) || !Read_word_le(file, &block_length))
+        break;
+      if (0 != memcmp(sig, "MJH", 3))
+        break;
+      GFX2_Log(GFX2_DEBUG, "  %.3s block %u\n", sig, block_length);
+      file_size -= 5;
+      while (block_length > 0)
+      {
+        byte code;
+        if (!Read_byte(file, &code))
+          break;
+        file_size--;
+        if (code == 1)
+        {
+          byte repeat, value;
+          if (!Read_byte(file, &repeat) || !Read_byte(file, &value))
+            break;
+          file_size -= 2;
+          do
+          {
+            cpc_ram[load_address + i++] = value;
+            block_length--;
+          }
+          while(--repeat != 0);
+        }
+        else
+        {
+          cpc_ram[load_address + i++] = code;
+          block_length--;
+        }
+      }
+      GFX2_Log(GFX2_DEBUG, "  unpacked %d bytes. remaining bytes in file=%lu\n",
+               i, file_size);
+    }
+    while(file_size > 0 && i < 16384);
+  }
+  fclose(file);
+
+  if (i > 5)
+  {
+    win_width = cpc_ram[load_address + i - 4] + (cpc_ram[load_address + i - 3] << 8);  // in bits
+    win_height = cpc_ram[load_address + i - 2];
+    if (((win_width + 7) >> 3) * win_height + 5 == i) // that's a WIN file !
+    {
+      width = win_width >> (2 - mode);
+      height = win_height;
+      is_win = 1;
+      columns = (win_width + 7) >> 3;
+      GFX2_Log(GFX2_DEBUG, ".WIN file detected len=%d (%d,%d) %dcols %02X %02X %02X %02X %02X\n",
+          i, width, height, columns,
+          cpc_ram[load_address + i - 5], cpc_ram[load_address + i - 4], cpc_ram[load_address + i - 3],
+          cpc_ram[load_address + i - 2], cpc_ram[load_address + i - 1]);
+    }
+    else
+    {
+      GFX2_Log(GFX2_DEBUG, ".SCR file. Data length %d\n", i);
+      if (load_address == 0x170)
+      {
+        // fichier iMPdraw v2
+        // http://orgams.wikidot.com/le-format-impdraw-v2
+        GFX2_Log(GFX2_DEBUG, "Detected \"%s\"\n", cpc_ram + load_address + 6);
+        mode = cpc_ram[load_address + 0x14] - 0x0e;
+        cpc_plus = cpc_ram[load_address + 0x3c];
+        GFX2_Log(GFX2_DEBUG, "Mode %d CPC %d\n", (int)mode, (int)cpc_plus);
+        for (addr = load_address + 0x1d; cpc_ram[addr] < 16; addr += 2)
+        {
+          GFX2_Log(GFX2_DEBUG, " R%d = &H%02x = %d\n", cpc_ram[addr], cpc_ram[addr+1], cpc_ram[addr+1]);
+          // see http://www.cpcwiki.eu/index.php/CRTC#The_6845_Registers
+          switch(cpc_ram[addr])
+          {
+            case 1:
+              columns = cpc_ram[addr+1] * 2;
+              break;
+            case 6:
+              height = cpc_ram[addr+1] * 8;
+              break;
+            case 12:
+              display_start = ((cpc_ram[addr+1] & 0x30) << 10) | ((cpc_ram[addr+1] & 0x03) << 9);
+              GFX2_Log(GFX2_DEBUG, "  display_start &H%04X\n", display_start);
+           }
+        }
+        snprintf(context->Comment, COMMENT_SIZE, "%s mode %d %s",
+                 cpc_ram + load_address + 7, mode, cpc_plus ? "CPC+" : "");
+        if (cpc_plus)
+        {
+          // palette at 0x801 (mode at 0x800 ?)
+          GFX2_LogHexDump(GFX2_DEBUG, "", cpc_ram, 0x800, 0x21);
+          cpc_plus_pal = cpc_ram + 0x801;
+        }
+        else
+        {
+          int j;
+          // palette at 0x7f00
+          GFX2_LogHexDump(GFX2_DEBUG, "", cpc_ram, 0x7f00, 16);
+          for (j = 0; j < 16; j++)
+            pal_data[12*j] = cpc_ram[0x7f00 + j];
+        }
+      }
+      else if (load_address == 0x200)
+      {
+        /* from HARLEY.SCR :
+        0800  00 = mode
+        0801-0810 palette (Firmware colors)
+        0811  21 47 08      LD HL,0847  ; OVERSCAN_REG_VALUES
+        0814  cd 36 08      CALL 0836 ; LOAD_CRTC_REGS
+        0817  3a 00 08      LD A,(0800) ; MODE
+        081a  cd 1c bd      CALL BD1C ; Set screen mode
+        081d  21 01 08      LD HL,0801  ; PALETTE
+        0820  af            XOR A
+            LOOP:
+        0821  4e            LD C,(HL)
+        0822  41            LD B,C
+        0823  f5            PUSH AF
+        0824  e5            PUSH HL
+        0825  cd 32 bc      CALL BC32   ; SET ink A to color B,C
+        0828  e1            POP HL
+        0829  f1            POP AF
+        082a  23            INC HL
+        082b  3c            INC A
+        082c  fe 10         CMP 10
+        082e  20 f1         JR NZ,0821  ; LOOP
+        0830  cd 18 bb      CALL BB18 ; Wait key press
+        0833  21 55 08      LD HL,0855  ; STANDARD_REG_VALUES
+            LOAD_CRTC_REGS:
+        0836  01 00 bc      LD BC,BC00
+            LOOP_CRTC:
+        0839  7e            LD A,(HL)
+        083a  a7            AND A
+        083b  c8            RET Z
+        083c  ed 79         OUT (C),A
+        083e  04            INC B
+        083f  23            INC HL
+        0840  7e            LD A,(HL)
+        0841  ed 79         OUT (C),A
+        0843  23            INC HL
+        0844  05            DEC B
+        0845  18 f2         JR 0839 ; LOOP_CRTC
+            OVERSCAN_REG_VALUES:
+        0847  01 30  02 32  06 22  07 23  0c 0d  0d 00  00 00
+            STANDARD_REG_VALUES:
+        0855  01 28  02 2e  06 19  07 1e  0c 30  00 00
+        */
+        int j;
+        static const byte CPC_Firmware_Colors[] = {
+          0x54, 0x44, 0x55, 0x5c, 0x58, 0x5d, 0x4c, 0x45, 0x4d,
+          0x56, 0x46, 0x57, 0x5e, 0x40, 0x5f, 0x4e, 0x47, 0x4f,
+          0x52, 0x42, 0x53, 0x5a, 0x59, 0x5b, 0x4a, 0x43, 0x4b };
+        mode = cpc_ram[0x800];
+        for (j = 0; j < 16; j++)
+          pal_data[12*j] = CPC_Firmware_Colors[cpc_ram[0x801 + j]];
+        addr = 0x847;
+        if (cpc_ram[0x80bb] == 1)
+          addr = 0x80bb;
+        for (; cpc_ram[addr] > 0 && cpc_ram[addr] < 16; addr += 2)
+        {
+          GFX2_Log(GFX2_DEBUG, " R%d = &H%02x = %d\n", cpc_ram[addr], cpc_ram[addr+1], cpc_ram[addr+1]);
+          // see http://www.cpcwiki.eu/index.php/CRTC#The_6845_Registers
+          switch(cpc_ram[addr])
+          {
+            case 1:
+              columns = cpc_ram[addr+1] * 2;
+              break;
+            case 6:
+              height = cpc_ram[addr+1] * 8;
+              break;
+            case 12:
+              display_start = (display_start & 0x00ff) | ((cpc_ram[addr+1] & 0x30) << 10) | ((cpc_ram[addr+1] & 0x03) << 9);
+              break;
+            case 13:
+              display_start = (display_start & 0xff00) | cpc_ram[addr+1];
+           }
+         }
+      }
+      if (i >= 30000)
+      {
+        height = 272; columns = 96;
+      }
+    }
+  }
+
+  switch (mode)
+  {
+    case 0:
+      width = columns * 2;
+      bpp = 4;
+      ratio = PIXEL_WIDE;
+      break;
+    case 1:
+      width = columns * 4;
+      bpp = 2;
+      ratio = PIXEL_SIMPLE;
+      break;
+    case 2:
+      width = columns * 8;
+      bpp = 1;
+      ratio = PIXEL_TALL;
+      break;
+    default:
+      return; // unsupported
+  }
+
+  if (Config.Clear_palette)
+    memset(context->Palette,0,sizeof(T_Palette));
+  // Setup the palette (amstrad hardware palette)
+  CPC_set_HW_palette(context->Palette + 0x40);
+
+  // Set the palette for this picture
+  if (cpc_plus_pal)
+  {
+    for (i = 0; i < 16; i++)
+    {
+      context->Palette[i].G = cpc_plus_pal[i*2 + 1] * 0x11;
+      context->Palette[i].R = (cpc_plus_pal[i*2] >> 4) * 0x11;
+      context->Palette[i].B = (cpc_plus_pal[i*2] & 15) * 0x11;
+    }
+  }
+  else
+  {
+    for (i = 0; i < 16; i++)
+      context->Palette[i] = context->Palette[pal_data[12*i]];
+  }
+
+  File_error = 0;
+  Pre_load(context, width, height, real_file_size, FORMAT_SCR, ratio, bpp);
+
+  if (!is_win)
+  {
+    // Standard resolution files have the 200 lines stored in block
+    // of 25 lines of 80 bytes = 2000 bytes every 2048 bytes.
+    // so there are 48 bytes unused every 2048 bytes...
+    for (y = 0; y < 8; y++)
+    {
+      addr = display_start + 0x800 * y;
+      if (y > 0 && (display_start & 0x7ff))
+      {
+        if (!GFX2_is_mem_filled_with(cpc_ram + (addr & 0xf800), 0, display_start & 0x7ff))
+          GFX2_LogHexDump(GFX2_DEBUG, "SCR1 ", cpc_ram,
+                          addr & 0xf800, display_start & 0x7ff);
+      }
+      addr += (height >> 3) * columns;
+      block_length = (height >> 3) * columns + (display_start & 0x7ff);
+      if (block_length <= 0x800)
+      {
+        block_length = 0x800 - block_length;
+        if (!GFX2_is_mem_filled_with(cpc_ram + addr, 0, block_length))
+          GFX2_LogHexDump(GFX2_DEBUG, "SCR2 ", cpc_ram,
+                          addr, block_length);
+      }
+      else
+      {
+        block_length = 0x1000 - block_length;
+        if (!GFX2_is_mem_filled_with(cpc_ram + addr + 0x4000, 0, block_length))
+          GFX2_LogHexDump(GFX2_DEBUG, "SCR2 ", cpc_ram,
+                          addr + 0x4000, block_length);
+      }
+    }
+    //for (j = 0; j < i; j += 2048)
+    //  GFX2_LogHexDump(GFX2_DEBUG, "SCR ", cpc_ram, load_address + j + 2000, 48);
+  }
+
+  GFX2_Log(GFX2_DEBUG, "  display_start &H%04X\n", display_start);
+  for (y = 0; y < height; y++)
+  {
+    const byte * line;
+
+    if (is_win)
+      addr = display_start + y * columns;
+    else
+    {
+      addr = display_start + ((y >> 3) * columns);
+      addr = (addr & 0xC7FF) | ((addr & 0x800) << 3);
+      addr += (y & 7) << 11;
+    }
+    //GFX2_Log(GFX2_DEBUG, "line#%d &H%04X\n", y, addr);
+    line = cpc_ram + addr;
+    x = 0;
+    for (i = 0; i < columns; i++)
+    {
+      byte pixels = line[i];
+      switch (mode)
+      {
+        case 0:
+          Set_pixel(context, x++, y, (pixels & 0x80) >> 7 | (pixels & 0x08) >> 2 | (pixels & 0x20) >> 3 | (pixels & 0x02) << 2);
+          Set_pixel(context, x++, y, (pixels & 0x40) >> 6 | (pixels & 0x04) >> 1 | (pixels & 0x10) >> 2 | (pixels & 0x01) << 3);
+          break;
+        case 1:
+          do {
+            // upper nibble is 4 lower color bits, lower nibble is 4 upper color bits
+            Set_pixel(context, x++, y, (pixels & 0x80) >> 7 | (pixels & 0x08) >> 2);
+            pixels <<= 1;
+          }
+          while ((x & 3) != 0);
+          break;
+        case 2:
+          do {
+            Set_pixel(context, x++, y, (pixels & 0x80) >> 7);
+            pixels <<= 1;
+          }
+          while ((x & 7) != 0);
+      }
+    }
+  }
+
+  free(cpc_ram);
+}
+
+/**
+ * Save Amstrad SCR file
+ *
+ * guess mode from aspect ratio :
+ * - normal pixels are mode 1
+ * - wide pixels are mode 0
+ * - tall pixels are mode 2
+ *
+ * Mode and palette are stored in a .PAL file.
+ *
+ * The picture color index should be 0-15,
+ * The CPC Hardware palette is expected to be set (indexes 64 to 95)
+ *
+ * @todo Add possibility to set R9, R12, R13 values
+ * @todo Add OCP packing support
+ * @todo Add possibility to include AMSDOS header, with proper loading
+ *       address guessed from r12/r13 values.
+ */
+void Save_SCR(T_IO_Context * context)
+{
+  int i, j;
+  unsigned char* output;
+  unsigned long outsize = 0;
+  unsigned char r1 = 0;
+  int cpc_mode;
+  FILE* file;
+
+
+  switch(Pixel_ratio)
+  {
+    case PIXEL_WIDE:
+    case PIXEL_WIDE2:
+      cpc_mode = 0;
+      break;
+    case PIXEL_TALL:
+    case PIXEL_TALL2:
+    case PIXEL_TALL3:
+      cpc_mode = 2;
+      break;
+    default:
+      cpc_mode = 1;
+      break;
+  }
+
+  file = Open_file_write_with_alternate_ext(context, "pal");
+  if (file == NULL)
+    return;
+  if (!Write_byte(file, cpc_mode) || !Write_byte(file, 0) || !Write_byte(file, 0))
+  {
+    fclose(file);
+    return;
+  }
+  for (i = 0; i < 16; i++)
+  {
+    // search for the color in the HW palette (0x40-0x5F)
+    byte index = 0x40;
+    while ((index < 0x60) &&
+        !CPC_compare_colors(context->Palette + i, context->Palette + index))
+      index++;
+    if (index >= 0x60)
+    {
+      GFX2_Log(GFX2_WARNING, "Save_SCR() color #%i not found in CPC HW palette.\n", i);
+      index = 0x54 - i; // default
+    }
+    for (j = 0; j < 12; j++)  // write the same color for the 12 frames
+    {
+      Write_byte(file, index);
+    }
+  }
+  // border
+  for (j = 0; j < 12; j++)
+  {
+    Write_byte(file, 0x54); // black
+  }
+  // excluded inks
+  for (i = 0; i < 16; i++)
+  {
+    Write_byte(file, 0);
+  }
+  // protected inks
+  for (i = 0; i < 16; i++)
+  {
+    Write_byte(file, 0);
+  }
+  fclose(file);
+
+  output = raw2crtc(context, cpc_mode, 7, &outsize, &r1, 0x0C, 0);
+  GFX2_Log(GFX2_DEBUG, "Save_SCR() output=%p outsize=%lu r1=$%02X\n", output, outsize, r1);
+
+  if (output == NULL)
+    return;
+
+  file = Open_file_write(context);
+  if (file == NULL)
+    File_error = 1;
+  else
+  {
+    File_error = 0;
+    if (!Write_bytes(file, output, outsize))
+      File_error = 1;
+    fclose(file);
+  }
+  free (output);
+}
+
+/**
+ * Test for GO1/GO2/KIT - Amstrad Plus Graphos
+ *
+ * This format is made of 3 files
+ * .KIT hold the palette in "Kit4096" format. There are 16 colors each stored
+ * as 12 bit RGB in RB0G order.
+ * .GO1 and GO2 hold each half of the picture (top and bottom)
+ * The file always cover the whole display of the Plus (196*272 or so)
+ */
+void Test_GOS(T_IO_Context * context, FILE * file)
+{
+  FILE *file_oddeve;
+  unsigned long file_size = 0;
+
+  if (!CPC_check_AMSDOS(file, NULL, &file_size))
+    file_size = File_length_file(file);
+  if (file_size < 16383 || file_size > 16384) {
+    File_error = 1;
+    return;
+  }
+
+  file_oddeve = Open_file_read_with_alternate_ext(context, "GO2");
+  if (file_oddeve == NULL) {
+    File_error = 2;
+    return;
+  }
+  if (!CPC_check_AMSDOS(file_oddeve, NULL, &file_size))
+    file_size = File_length_file(file_oddeve);
+  fclose(file_oddeve);
+  if (file_size < 16383 || file_size > 16384) {
+    File_error = 3;
+    return;
+  }
+
+  File_error = 0;
+}
+
+
+/**
+ * Load GO1/GO2/KIT - Amstrad CPC Plus Graphos
+ */
+void Load_GOS(T_IO_Context* context)
+{
+  FILE *file;
+  unsigned long file_size;
+  int i;
+  int x, y;
+  byte * pixel_data;
+
+  if (!(file = Open_file_read(context)))
+  {
+      File_error = 1;
+      return;
+  }
+
+  if (CPC_check_AMSDOS(file, NULL, &file_size))
+    fseek(file, 128, SEEK_SET); // right after AMSDOS header
+  else
+    file_size = File_length_file(file);
+
+  context->Ratio = PIXEL_WIDE;
+  Pre_load(context, 192, 272, file_size, FORMAT_GOS, context->Ratio, 0);
+  context->Width = 192;
+  context->Height = 272;
+
+  // load pixels
+  pixel_data = GFX2_malloc(16384);
+  memset(pixel_data, 0, 16384);
+  Read_bytes(file, pixel_data, file_size);
+
+  i = 0;
+  for (y = 0; y < 168; y++) {
+    x = 0;
+    while (x < 192) {
+      byte pixels = pixel_data[i];
+      Set_pixel(context, x++, y, (pixels & 0x80) >> 7 | (pixels & 0x08) >> 2 | (pixels & 0x20) >> 3 | (pixels & 0x02) << 2);
+      Set_pixel(context, x++, y, (pixels & 0x40) >> 6 | (pixels & 0x04) >> 1 | (pixels & 0x10) >> 2 | (pixels & 0x01) << 3);
+      i++;
+    }
+
+    i += 0x800;
+    if (i > 0x3FFF) {
+      i -= 0x4000;
+    } else {
+      i -= 192 / 2;
+    }
+  }
+
+  fclose(file);
+
+  // load pixels from GO2
+  file = Open_file_read_with_alternate_ext(context, "GO2");
+  if (CPC_check_AMSDOS(file, NULL, &file_size))
+    fseek(file, 128, SEEK_SET); // right after AMSDOS header
+
+  Read_bytes(file, pixel_data, file_size);
+  i = 0;
+  for (y = 168; y < 272; y++) {
+    x = 0;
+    while (x < 192) {
+      byte pixels = pixel_data[i];
+      Set_pixel(context, x++, y, (pixels & 0x80) >> 7 | (pixels & 0x08) >> 2 | (pixels & 0x20) >> 3 | (pixels & 0x02) << 2);
+      Set_pixel(context, x++, y, (pixels & 0x40) >> 6 | (pixels & 0x04) >> 1 | (pixels & 0x10) >> 2 | (pixels & 0x01) << 3);
+      i++;
+    }
+
+    i += 0x800;
+    if (i > 0x3FFF) {
+      i -= 0x4000;
+    } else {
+      i -= 192 / 2;
+    }
+  }
+
+  fclose(file);
+
+  file = Open_file_read_with_alternate_ext(context, "KIT");
+  if (file == NULL) {
+    // There is no palette, but that's fine, we can still load the pixels
+    return;
+  }
+
+  if (CPC_check_AMSDOS(file, NULL, &file_size)) {
+    fseek(file, 128, SEEK_SET); // right after AMSDOS header
+  } else {
+    file_size = File_length_file(file);
+  }
+
+  if (Config.Clear_palette)
+    memset(context->Palette,0,sizeof(T_Palette));
+
+  File_error = 0;
+
+  if (file_size == 32)
+  {
+    for (i = 0; i < 16; i++)
+    {
+      uint16_t word;
+      if (!Read_word_le(file, &word))
+      {
+        File_error = 2;
+        return;
+      }
+
+      context->Palette[i].R = ((word >>  4) & 0xF) * 0x11;
+      context->Palette[i].G = ((word >>  8) & 0xF) * 0x11;
+      context->Palette[i].B = ((word >>  0) & 0xF) * 0x11;
+    }
+  }
+  else
+  {
+    // Setup the palette (amstrad hardware palette)
+    CPC_set_HW_palette(context->Palette + 0x40);
+    for (i = 0; i < 16; i++)
+    {
+      byte ink;
+      if (!Read_byte(file, &ink))
+      {
+        File_error = 2;
+        return;
+      }
+      context->Palette[i] = context->Palette[ink];
+    }
+  }
+
+  fclose(file);
+}
+
+/**
+ * Test for CM5 - Amstrad CPC "Mode 5" picture
+ *
+ * This is a format designed by SyX.
+ * There is one .GFX file in the usual amstrad format
+ * and a .CM5 file with the palette, which varies over time.
+ *
+ * CM5 file is 2049 bytes, GFX is 18432 bytes.
+ *
+ * @todo check CM5 contains only valid values [0x40-0x5f]
+ */
+void Test_CM5(T_IO_Context * context, FILE * file)
+{
+  // check cm5 file size == 2049 bytes
+  FILE *file_gfx;
+  long file_size;
+
+  File_error = 1;
+
+  file_size = File_length_file(file);
+  if (file_size != 2049)
+    return;
+
+  // check existence of a .GFX file with the same name
+  file_gfx = Open_file_read_with_alternate_ext(context, "gfx");
+  if (file_gfx == NULL)
+    return;
+  file_size = File_length_file(file_gfx);
+  fclose(file_gfx);
+  if (file_size != 18432)
+    return;
+
+  File_error = 0;
+}
+
+
+/**
+ * Load Amstrad CPC "Mode 5" picture
+ *
+ * Only support 288x256 resolution as the Mode 5 Viewer app only handles this
+ * single resoltion.
+ */
+void Load_CM5(T_IO_Context* context)
+{
+  // Ensure "8bit" constraint mode is switched on
+  // Set palette to the CPC hardware colors
+  // Load the palette data to the 4 colorlayers
+  FILE *file;
+  byte value = 0;
+  int mod=0;
+  short line = 0;
+  int tx, ty;
+  // for preview :
+  byte ink0;
+  byte ink1[256];
+  byte ink2[256];
+  byte ink3[256*6];
+
+  if (!(file = Open_file_read(context)))
+  {
+      File_error = 1;
+      return;
+  }
+
+  Pre_load(context, 48*6, 256, 2049, FORMAT_CM5, PIXEL_SIMPLE, 0);
+
+  if (Config.Clear_palette)
+  {
+    memset(context->Palette,0,sizeof(T_Palette));
+    // setup colors 0,1,2,3 to see something in the thumbnail preview of layer 5
+    context->Palette[1].R = 60;
+    context->Palette[2].B = 60;
+    context->Palette[3].G = 60;
+  }
+
+  // Setup the palette (amstrad hardware palette)
+  CPC_set_HW_palette(context->Palette + 0x40);
+
+  First_color_in_palette = 64;
+
+  if (!Read_byte(file, &ink0))
+    File_error = 2;
+
+  // This forces the creation of 5 layers total :
+  // Needed because the "pixel" functions will seek layer 4
+  Set_loading_layer(context, 4);
+  // Now select layer 1 again
+  Set_loading_layer(context, 0);
+
+  if (context->Type == CONTEXT_MAIN_IMAGE)
+  {
+    Set_image_mode(context, IMAGE_MODE_MODE5);
+
+    // Fill layer with color we just read (Layer 1 - INK 0)
+    for(ty=0; tyHeight; ty++)
+      for(tx=0; txWidth; tx++)
+        Set_pixel(context, tx, ty, ink0);
+  }
+
+  while(Read_byte(file, &value))
+  {
+    switch(mod)
+    {
+      case 0:
+        // This is color for layer 2 - INK 1
+        Set_loading_layer(context, 1);
+        for(tx=0; txWidth; tx++)
+          Set_pixel(context, tx, line, value);
+        ink1[line] = value;
+        break;
+      case 1:
+        // This is color for layer 3 - INK 2
+        Set_loading_layer(context, 2);
+        for(tx=0; txWidth; tx++)
+          Set_pixel(context, tx, line, value);
+        ink2[line] = value;
+        break;
+      default:
+        // This is color for a block in layer 4 - INK 3
+        Set_loading_layer(context, 3);
+        for(tx=(mod-2)*48; tx<(mod-1)*48; tx++)
+          Set_pixel(context, tx, line, value);
+        ink3[line*6+(mod-2)] = value;
+        break;
+    }
+    mod++;
+    if (mod > 7)
+    {
+      mod = 0;
+      line++;
+    }
+  }
+
+  fclose(file);
+
+  // Load the pixeldata to the 5th layer
+  file = Open_file_read_with_alternate_ext(context, "gfx");
+  if (file == NULL)
+  {
+    File_error = 1;
+    return;
+  }
+  Set_loading_layer(context, 4);
+
+  if (context->Type == CONTEXT_PREVIEW)
+    for (ty = 0; ty < 256; ty++)
+      for (tx = 0; tx < 48*6; )
+      {
+        Read_byte(file, &value);
+        for (mod = 0; mod < 4; mod++, tx++, value <<= 1)
+        {
+          switch(3 ^ (((value&0x80) >> 7) | ((value&0x8)>>2)))  // INK
+          {
+            case 0:
+              Set_pixel(context, tx, ty, ink0);
+              break;
+            case 1:
+              Set_pixel(context, tx, ty, ink1[ty]);
+              break;
+            case 2:
+              Set_pixel(context, tx, ty, ink2[ty]);
+              break;
+            default:
+              Set_pixel(context, tx, ty, ink3[ty*6+(tx/48)]);
+          }
+        }
+      }
+  else
+    for (ty = 0; ty < 256; ty++)
+      for (tx = 0; tx < 48*6; )
+      {
+        Read_byte(file, &value);
+        Set_pixel(context, tx++, ty, 3 ^ (((value&0x80) >> 7) | ((value&0x8)>>2)));
+        Set_pixel(context, tx++, ty, 3 ^ (((value&0x40) >> 6) | ((value&0x4)>>1)));
+        Set_pixel(context, tx++, ty, 3 ^ (((value&0x20) >> 5) | ((value&0x2)>>0)));
+        Set_pixel(context, tx++, ty, 3 ^ (((value&0x10) >> 4) | ((value&0x1)<<1)));
+      }
+
+  fclose(file);
+
+}
+
+
+void Save_CM5(T_IO_Context* context)
+{
+  FILE* file;
+  int tx, ty;
+
+  // TODO: Check picture has 5 layers
+  // TODO: Check the constraints on the layers
+  // Layer 1 : 1 color Only
+  // Layer 2 and 3 : 1 color/line
+  // Layer 4 : 1 color / 48x1 block
+  // TODO: handle filesize
+
+  if (!(file = Open_file_write(context)))
+  {
+    File_error = 1;
+    return;
+  }
+  setvbuf(file, NULL, _IOFBF, 64*1024);
+
+  // Write layer 0
+  Set_saving_layer(context, 0);
+  Write_byte(file, Get_pixel(context, 0, 0));
+  for(ty = 0; ty < 256; ty++)
+  {
+    Set_saving_layer(context, 1);
+    Write_byte(file, Get_pixel(context, 0, ty));
+    Set_saving_layer(context, 2);
+    Write_byte(file, Get_pixel(context, 0, ty));
+    Set_saving_layer(context, 3);
+    for(tx = 0; tx < 6; tx++)
+    {
+      Write_byte(file, Get_pixel(context, tx*48, ty));
+    }
+  }
+
+  fclose(file);
+
+  // Now the pixeldata
+  if (!(file = Open_file_write_with_alternate_ext(context, "gfx")))
+  {
+    File_error = 2;
+    return;
+  }
+  setvbuf(file, NULL, _IOFBF, 64*1024);
+
+  Set_saving_layer(context, 4);
+
+  for (ty = 0; ty < 256; ty++)
+  {
+    for (tx = 0; tx < 48*6; tx+=4)
+    {
+      byte code = 0;
+      byte pixel;
+
+      pixel = 3-Get_pixel(context, tx+3, ty);
+      code |= (pixel&2)>>1 | ((pixel & 1)<<4);
+      pixel = 3-Get_pixel(context, tx+2, ty);
+      code |= ((pixel&2)<<0) | ((pixel & 1)<<5);
+      pixel = 3-Get_pixel(context, tx+1, ty);
+      code |= ((pixel&2)<<1) | ((pixel & 1)<<6);
+      pixel = 3-Get_pixel(context, tx, ty);
+      code |= ((pixel&2)<<2) | ((pixel & 1)<<7);
+      Write_byte(file, code);
+    }
+  }
+
+  fclose(file);
+  File_error = 0;
+
+}
+
+
+/* Amstrad CPC 'PPH' for Perfect Pix.
+// This is a format designed by Rhino.
+// There are 3 modes:
+// - Mode 'R': 1:1 pixels, 16 colors from the CPC 27 color palette.
+//   (this is implemented on CPC as two pictures with wide pixels, the "odd" one
+//   being shifted half a pixel to the right), and flipping)
+// - Mode 'B0': wide pixels, up to 126 out of 378 colors.
+//   (this is implemented as two pictures with wide pixels, sharing the same 16
+//   color palette, and flipping)
+// - Mode 'B1': 1:1 pixels, 1 fixed color, up to 34 palettes of 9 colors
+//   (actually 4 colors + flipping)
+//
+// - The standard CPC formats can also be encapsulated into a PPH file.
+//
+// http://www.pouet.net/prod.php?which=67770#c766959
+*/
+void Test_PPH(T_IO_Context * context, FILE * file)
+{
+  FILE *file_oddeve;
+  byte buffer[6];
+  unsigned long file_size;
+  unsigned int w, h;
+  unsigned int expected;
+
+  File_error = 1;
+
+  // First check file size is large enough to hold the header
+  file_size = File_length_file(file);
+  if (file_size < 11) {
+    File_error = 1;
+    return;
+  }
+
+  // File is large enough for the header, now check if the data makes some sense
+  if (!Read_bytes(file, buffer, 6))
+    return;
+  if (buffer[0] > 5) {
+    // Unknown mode
+    File_error = 2;
+    return;
+  }
+
+  w = buffer[1] | (buffer[2] << 8);
+  if (w < 2 || w > 384) {
+    // Invalid width
+    File_error = 3;
+    return;
+  }
+
+  h = buffer[3] | (buffer[4] << 8);
+  if (h < 1 || h > 272) {
+    // Invalid height
+    File_error = 4;
+    return;
+  }
+
+  if (buffer[5] < 1 || buffer[5] > 28)
+  {
+    // Invalid palettes count
+    File_error = 5;
+    return;
+  }
+  expected = 6; // Size of header
+  switch(buffer[0])
+  {
+    case 0:
+    case 3:
+    case 4:
+      // Palette size should be 16 bytes, only 1 palette.
+      if (buffer[5] != 1) {
+        File_error = 7;
+        return;
+      }
+      expected += 16;
+      break;
+
+    case 1:
+    case 5:
+      expected += buffer[5] * 5 - 1;
+      break;
+
+    case 2:
+      // Palette size should be 2 bytes
+      if (buffer[5] != 1) {
+        File_error = 7;
+        return;
+      }
+      expected += 2;
+      break;
+  }
+
+  if (file_size != expected)
+  {
+    File_error = 6;
+    return;
+  }
+
+  // check existence of .ODD/.EVE files with the same name
+  // and the right size
+  expected = w * h / 4;
+  file_oddeve = Open_file_read_with_alternate_ext(context, "odd");
+  if (file_oddeve == NULL)
+    return;
+  file_size = File_length_file(file_oddeve);
+  fclose (file_oddeve);
+  if (file_size != expected)
+  {
+    File_error = 8;
+    return;
+  }
+  file_oddeve = Open_file_read_with_alternate_ext(context, "eve");
+  if (file_oddeve == NULL)
+    return;
+  file_size = File_length_file(file_oddeve);
+  fclose(file_oddeve);
+  if (file_size != expected)
+  {
+    File_error = 8;
+    return;
+  }
+  File_error = 0;
+}
+
+
+static uint8_t pph_blend(uint8_t a, uint8_t b)
+{
+	uint32_t h,l;
+	if (a > b) { h = a; l = b; }
+	else       { h = b; l = a; }
+
+	return (23 * h + 9 * l) / 32;
+}
+
+
+void Load_PPH(T_IO_Context* context)
+{
+  FILE *file;
+  FILE *feven;
+
+  // Read in the header
+  uint8_t mode;
+  uint16_t width;
+  uint16_t height;
+  uint8_t npal;
+  int i,j;
+  uint8_t a,b,c,d;
+  int file_size;
+  uint8_t pl[16];
+
+  static const T_Components CPCPAL[27] =
+  {
+      { 0x00, 0x02, 0x01 }, { 0x00, 0x02, 0x6B }, { 0x0C, 0x02, 0xF4 },
+      { 0x6C, 0x02, 0x01 }, { 0x69, 0x02, 0x68 }, { 0x6C, 0x02, 0xF2 },
+      { 0xF3, 0x05, 0x06 }, { 0xF0, 0x02, 0x68 }, { 0xF3, 0x02, 0xF4 },
+      { 0x02, 0x78, 0x01 }, { 0x00, 0x78, 0x68 }, { 0x0C, 0x7B, 0xF4 },
+      { 0x6E, 0x7B, 0x01 }, { 0x6E, 0x7D, 0x6B }, { 0x6E, 0x7B, 0xF6 },
+      { 0xF3, 0x7D, 0x0D }, { 0xF3, 0x7D, 0x6B }, { 0xFA, 0x80, 0xF9 },
+      { 0x02, 0xF0, 0x01 }, { 0x00, 0xF3, 0x6B }, { 0x0F, 0xF3, 0xF2 },
+      { 0x71, 0xF5, 0x04 }, { 0x71, 0xF3, 0x6B }, { 0x71, 0xF3, 0xF4 },
+      { 0xF3, 0xF3, 0x0D }, { 0xF3, 0xF3, 0x6D }, { 0xFF, 0xF3, 0xF9 }
+  };
+
+  if (!(file = Open_file_read(context)))
+  {
+      File_error = 1;
+      return;
+  }
+
+  file_size=File_length_file(file);
+
+  Read_byte(file, &mode);
+  Read_word_le(file, &width);
+  Read_word_le(file, &height);
+  Read_byte(file, &npal);
+
+  if (npal > 16)
+      npal = 16;
+
+  // Switch to the proper aspect ratio
+  switch (mode)
+  {
+      case 0:
+      case 4:
+        context->Ratio = PIXEL_WIDE;
+        width /= 2;
+        break;
+
+      case 2:
+        context->Ratio = PIXEL_TALL;
+        break;
+
+      case 1:
+      case 5:
+      case 3:
+        context->Ratio = PIXEL_SIMPLE;
+        break;
+  }
+
+  Pre_load(context, width, height, file_size, FORMAT_PPH, context->Ratio, 0);
+
+  context->Width = width;
+  context->Height = height;
+
+  // First of all, detect the mode
+  // 0, 1, 2 > Load as with SCR files?
+  // R(3)    > Load as single layer, square pixels, 16 colors
+  // B0(4)   > Load as single layer, wide pixels, expand palette with colorcycling
+  // B1(5)   > Load as ???
+  //           Maybe special mode similar to mode5, with 2 layers + auto-flicker?
+
+  switch (mode)
+  {
+      case 0:
+      case 3: // R
+          // 16-color palette
+          for (i = 0; i < 16; i++)
+          {
+              uint8_t color;
+              Read_byte(file, &color);
+              context->Palette[i] = CPCPAL[color];
+          }
+          break;
+
+      case 1:
+      case 5: // B1
+      {
+          // Single or multiple 4-color palettes
+          uint8_t base[4];
+          for (j = 0; j < npal; j++)
+          {
+            for (i = 0; i < 4; i++)
+            {
+              Read_byte(file,&base[i]);
+            }
+            for (i = 0; i < 16; i++)
+            {
+              context->Palette[i + 16*j].R = pph_blend(
+                  CPCPAL[base[i & 3]].R, CPCPAL[base[i >> 2]].R);
+              context->Palette[i + 16*j].G = pph_blend(
+                  CPCPAL[base[i & 3]].G, CPCPAL[base[i >> 2]].G);
+              context->Palette[i + 16*j].B = pph_blend(
+                  CPCPAL[base[i & 3]].B, CPCPAL[base[i >> 2]].B);
+            }
+            // TODO this byte marks where this palette stops being used and the
+            // next starts. We must handle this!
+            Read_byte(file,&pl[j]);
+          }
+          pl[npal - 1] = 255;
+          break;
+      }
+
+      case 2:
+          // Single 2-color palette
+          break;
+
+      case 4: // B0
+      {
+          // Single 16-color palette + flipping, need to expand palette and
+          // setup colorcycling ranges.
+          uint8_t base[16];
+          for (i = 0; i < 16; i++)
+          {
+              Read_byte(file,&base[i]);
+          }
+
+          for (i = 0; i < 256; i++)
+          {
+              context->Palette[i].R = pph_blend(
+                  CPCPAL[base[i & 15]].R, CPCPAL[base[i >> 4]].R);
+              context->Palette[i].G = pph_blend(
+                  CPCPAL[base[i & 15]].G, CPCPAL[base[i >> 4]].G);
+              context->Palette[i].B = pph_blend(
+                  CPCPAL[base[i & 15]].B, CPCPAL[base[i >> 4]].B);
+          }
+      }
+      break;
+  }
+
+  fclose(file);
+
+  // Load the picture data
+  // There are two pages, each storing bytes in the CPC vram format but lines in
+  // linear order.
+  file = Open_file_read_with_alternate_ext(context, "odd");
+  if (file == NULL)
+  {
+    File_error = 3;
+    return;
+  }
+  feven = Open_file_read_with_alternate_ext(context, "eve");
+  if (feven == NULL)
+  {
+    File_error = 4;
+    fclose(file);
+    return;
+  }
+
+  c = 0;
+  d = 0;
+
+  for (j = 0; j < height; j++)
+  {
+      for (i = 0; i < width;)
+      {
+          uint8_t even, odd;
+          Read_byte(feven, &even);
+          Read_byte(file, &odd);
+
+          switch (mode)
+          {
+              case 4:
+                a = ((even & 0x02) << 2) | ((even & 0x08) >> 2)
+                  | ((even & 0x20) >> 3) | ((even & 0x80) >> 7);
+                a <<= 4;
+                a |= ((odd & 0x02) << 2) | (( odd & 0x08) >> 2)
+                  | (( odd & 0x20) >> 3) | (( odd & 0x80) >> 7);
+
+                b = ((even & 0x01) << 3) | ((even & 0x04) >> 1)
+                  | ((even & 0x10) >> 2) | ((even & 0x40) >> 6);
+                b <<= 4;
+                b |= ((odd & 0x01) << 3) | (( odd & 0x04) >> 1)
+                  | (( odd & 0x10) >> 2) | (( odd & 0x40) >> 6);
+
+                Set_pixel(context, i++, j, a);
+                Set_pixel(context, i++, j, b);
+                break;
+
+              case 3:
+                a = ((even & 0x02) << 2) | ((even & 0x08) >> 2)
+                  | ((even & 0x20) >> 3) | ((even & 0x80) >> 7);
+                b = (( odd & 0x02) << 2) | (( odd & 0x08) >> 2)
+                  | (( odd & 0x20) >> 3) | (( odd & 0x80) >> 7);
+                c = ((even & 0x01) << 3) | ((even & 0x04) >> 1)
+                  | ((even & 0x10) >> 2) | ((even & 0x40) >> 6);
+                d = (( odd & 0x01) << 3) | (( odd & 0x04) >> 1)
+                  | (( odd & 0x10) >> 2) | (( odd & 0x40) >> 6);
+                Set_pixel(context, i++, j, j & 1 ? b : a);
+                Set_pixel(context, i++, j, j & 1 ? a : b);
+                Set_pixel(context, i++, j, j & 1 ? d : c);
+                Set_pixel(context, i++, j, j & 1 ? c : d);
+                break;
+
+              case 5:
+                if (d >= pl[c])
+                {
+                    d = 0;
+                    c++;
+                }
+                a = ((even & 0x80) >> 6) | ((even & 0x08) >> 3);
+                b = (( odd & 0x80) >> 6) | (( odd & 0x08) >> 3);
+                Set_pixel(context, i++, j, a + (b << 2) + c * 16);
+                a = ((even & 0x40) >> 5) | ((even & 0x04) >> 2);
+                b = (( odd & 0x40) >> 5) | (( odd & 0x04) >> 2);
+                Set_pixel(context, i++, j, a + (b << 2) + c * 16);
+                a = ((even & 0x20) >> 4) | ((even & 0x02) >> 1);
+                b = (( odd & 0x20) >> 4) | (( odd & 0x02) >> 1);
+                Set_pixel(context, i++, j, a + (b << 2) + c * 16);
+                a = ((even & 0x10) >> 3) | ((even & 0x01) >> 0);
+                b = (( odd & 0x10) >> 3) | (( odd & 0x01) >> 0);
+                Set_pixel(context, i++, j, a + (b << 2) + c * 16);
+
+                break;
+
+              default:
+                File_error = 2;
+                return;
+          }
+
+      }
+      d++;
+  }
+  fclose(file);
+  fclose(feven);
+
+  File_error = 0;
+}
+
+void Save_PPH(T_IO_Context* context)
+{
+  (void)context; // unused
+    // TODO
+
+    // Detect mode
+    // Wide pixels => B0 (4)
+    // Square pixels:
+    // - 16 colors used => R
+    // - more colors used => B1 (if <16 colors per line)
+
+    // Check palette
+    // B0: use diagonal: 0, 17, 34, ... (assume the other are mixes)
+    // R: use 16 used colors (or 16 first?)
+    // B1: find the 16 colors used in a line? Or assume they are in-order already?
+}
diff --git a/src/miscfileformats.c b/src/miscfileformats.c
index 26b693b3..88558348 100644
--- a/src/miscfileformats.c
+++ b/src/miscfileformats.c
@@ -41,7 +41,6 @@
 
 #include "global.h"
 #include "io.h"
-#include "libraw2crtc.h"
 #include "loadsave.h"
 #include "loadsavefuncs.h"
 #include "misc.h"
@@ -1441,1444 +1440,6 @@ void Save_KCF(T_IO_Context * context)
 }
 
 
-/**
- * Test for SCR file (Amstrad CPC)
- *
- * SCR file format is from "Advanced OCP Art Studio" :
- * http://www.cpcwiki.eu/index.php/Format:Advanced_OCP_Art_Studio_File_Formats
- *
- * .WIN "window" format is also supported.
- *
- * For now we check the presence of a valid PAL file.
- * If the PAL file is not there the pixel data may still be valid.
- * The file size depends on the screen resolution.
- * An AMSDOS header would be a good indication but in some cases it may not
- * be there.
- */
-void Test_SCR(T_IO_Context * context, FILE * file)
-{
-  // http://orgams.wikidot.com/le-format-impdraw-v2
-  // http://orgams.wikidot.com/les-fichiers-win-compatibles-ocp-art-studio
-  FILE * pal_file;
-  unsigned long pal_size, file_size;
-  byte mode, color_anim_flag;
-  word loading_address = 0;
-
-  File_error = 1;
-
-  if (CPC_check_AMSDOS(file, &loading_address, &file_size))
-  {
-    if (loading_address == 0x170) // iMPdraw v2
-    {
-      byte buffer[0x90];
-      fseek(file, 128, SEEK_SET); // right after AMSDOS header
-      Read_bytes(file, buffer, 0x90);
-      GFX2_LogHexDump(GFX2_DEBUG, "", buffer, 0, 0x90);
-      File_error = 0;
-      return;
-    }
-    else if ((loading_address == 0x200 || loading_address == 0xc000) && file_size > 16000)
-    {
-      File_error = 0;
-      return;
-    }
-  }
-  else
-    file_size = File_length_file(file);
-
-  if (file_size > 16384*2)
-    return;
-
-  // requires the PAL file
-  pal_file = Open_file_read_with_alternate_ext(context, "pal");
-  if (pal_file == NULL)
-    return;
-  /** @todo the palette data can be hidden in the 48 "empty" bytes
-   * every 2048 bytes of a standard resolution SCR file.
-   * So we should detect the hidden Z80 code and load them.
-   * Load address of file is C000. Z80 code :
-   * C7D0: 3a d0 d7 cd 1c bd 21 d1 d7 46 48 cd 38 bc af 21 | :.....!..FH.8..!
-   * C7E0: d1 d7 46 48 f5 e5 cd 32 bc e1 f1 23 3c fe 10 20 | ..FH...2...#<.. 
-   * C7F0: f1 c3 18 bb 00 00 00 00 00 00 00 00 00 00 00 00 | ................
-   * mode and palette :
-   * D7D0: 00 1a 00 0c 03 0b 01 0d 17 10 02 0f 09 19 06 00 | ................
-   * https://gitlab.com/GrafX2/grafX2/merge_requests/121#note_119964168
-   */
-
-
-  if (CPC_check_AMSDOS(pal_file, NULL, &pal_size))
-    fseek(pal_file, 128, SEEK_SET); // right after AMSDOS header
-  else
-  {
-    pal_size = File_length_file(pal_file);
-    fseek(pal_file, 0, SEEK_SET);
-  }
-
-  if (pal_size != 239)
-  {
-    fclose(pal_file);
-    return;
-  }
-
-  if (!Read_byte(pal_file, &mode) || !Read_byte(pal_file, &color_anim_flag))
-  {
-    fclose(pal_file);
-    return;
-  }
-  GFX2_Log(GFX2_DEBUG, "Test_SCR() mode=%d color animation flag %02X\n", mode, color_anim_flag);
-  if (mode <= 2 && (color_anim_flag == 0 || color_anim_flag == 0xff))
-    File_error = 0;
-  fclose(pal_file);
-}
-
-/**
- * Load Advanced OCP Art Studio files (Amstrad CPC)
- *
- * Only standard resolution files (Mode 0 160x200, mode 1 320x200 and
- * mode 2 640x200) are supported. The .PAL file presence is required.
- * "MJH" RLE packing is supported.
- *
- * .WIN "window" format is also supported.
- *
- * @todo Ask user for screen size (or register values) in order to support
- * non standard resolutions.
- */
-void Load_SCR(T_IO_Context * context)
-{
-    // The Amstrad CPC screen memory is mapped in a weird mode, somewhere
-    // between bitmap and textmode. Basically the only way to decode this is to
-    // emulate the video chip and read the bytes as needed...
-    // Moreover, the hardware allows the screen to have any size from 8x1 to
-    // 800x273 pixels, and there is no indication of that in the file besides
-    // its size. It can also use any of the 3 screen modes. Fortunately this
-    // last bit of information is stored in the palette file.
-    // Oh, and BTW, the picture can be offset, and it's even usual to do it,
-    // because letting 128 pixels unused at the beginning of the file make it a
-    // lot easier to handle screens using more than 16K of VRam.
-    // The pixel encoding change with the video mode so we have to know that
-    // before attempting to load anything...
-    // As if this wasn't enough, Advanced OCP Art Studio, the reference tool on
-    // Amstrad, can use RLE packing when saving files, meaning we also have to
-    // handle that.
-
-    // All this mess enforces us to load (and unpack if needed) the file to a
-    // temporary 32k buffer before actually decoding it.
-  FILE * pal_file, * file;
-  unsigned long real_file_size, file_size, amsdos_file_size = 0;
-  word addr;
-  word load_address = 0x4000; // default for OCP Art studio
-  word display_start = 0x4000;
-  byte mode, color_anim_flag, color_anim_delay;
-  byte pal_data[236]; // 12 palettes of 16+1 colors + 16 excluded inks + 16 protected inks
-  word width, height = 200;
-  byte bpp;
-  enum PIXEL_RATIO ratio;
-  byte * cpc_ram;
-  word x, y;
-  int i;
-  byte sig[3];
-  word block_length;
-  word win_width, win_height;
-  int is_win = 0;
-  int columns = 80;
-  int cpc_plus = 0;
-  const byte * cpc_plus_pal = NULL;
-
-  File_error = 1;
-  // requires the PAL file for OCP Art studio files
-  pal_file = Open_file_read_with_alternate_ext(context, "pal");
-  if (pal_file != NULL)
-  {
-    file_size = File_length_file(pal_file);
-    if (CPC_check_AMSDOS(pal_file, NULL, &file_size))
-      fseek(pal_file, 128, SEEK_SET); // right after AMSDOS header
-    else
-      fseek(pal_file, 0, SEEK_SET);
-    if (!Read_byte(pal_file, &mode) || !Read_byte(pal_file, &color_anim_flag)
-          || !Read_byte(pal_file, &color_anim_delay) || !Read_bytes(pal_file, pal_data, 236))
-    {
-      GFX2_Log(GFX2_WARNING, "Load_SCR() failed to load .PAL file\n");
-      fclose(pal_file);
-      return;
-    }
-    fclose(pal_file);
-    GFX2_Log(GFX2_DEBUG, "Load_SCR() mode=%d color animation flag=%02X delay=%u\n",
-             mode, color_anim_flag, color_anim_delay);
-  }
-
-  file = Open_file_read(context);
-  if (file == NULL)
-    return;
-  file_size = File_length_file(file);
-  real_file_size = file_size;
-  if (CPC_check_AMSDOS(file, &load_address, &amsdos_file_size))
-  {
-    display_start = load_address;
-    if (file_size < (amsdos_file_size + 128))
-    {
-      GFX2_Log(GFX2_ERROR, "Load_SCR() mismatch in file size. AMSDOS file size %lu, should be %lu\n", amsdos_file_size, file_size - 128);
-      fclose(file);
-      return;
-    }
-    else if (file_size > (amsdos_file_size + 128))
-      GFX2_Log(GFX2_INFO, "Load_SCR() %lu extra bytes at end of file\n", file_size - 128 - amsdos_file_size);
-    fseek(file, 128, SEEK_SET); // right after AMSDOS header
-    file_size = amsdos_file_size;
-  }
-  else
-    fseek(file, 0, SEEK_SET);
-
-  if (!Read_bytes(file, sig, 3) || !Read_word_le(file, &block_length))
-  {
-    fclose(file);
-    return;
-  }
-  fseek(file, -5, SEEK_CUR);
-
-  cpc_ram = GFX2_malloc(64*1024);
-  memset(cpc_ram, 0, 64*1024);
-
-  if (0 != memcmp(sig, "MJH", 3) || block_length > 16384)
-  {
-    // raw data
-    Read_bytes(file, cpc_ram + load_address, file_size);
-    i = file_size;
-  }
-  else
-  {
-    // MJH packed format
-    i = 0;
-    do
-    {
-      if (!Read_bytes(file, sig, 3) || !Read_word_le(file, &block_length))
-        break;
-      if (0 != memcmp(sig, "MJH", 3))
-        break;
-      GFX2_Log(GFX2_DEBUG, "  %.3s block %u\n", sig, block_length);
-      file_size -= 5;
-      while (block_length > 0)
-      {
-        byte code;
-        if (!Read_byte(file, &code))
-          break;
-        file_size--;
-        if (code == 1)
-        {
-          byte repeat, value;
-          if (!Read_byte(file, &repeat) || !Read_byte(file, &value))
-            break;
-          file_size -= 2;
-          do
-          {
-            cpc_ram[load_address + i++] = value;
-            block_length--;
-          }
-          while(--repeat != 0);
-        }
-        else
-        {
-          cpc_ram[load_address + i++] = code;
-          block_length--;
-        }
-      }
-      GFX2_Log(GFX2_DEBUG, "  unpacked %d bytes. remaining bytes in file=%lu\n",
-               i, file_size);
-    }
-    while(file_size > 0 && i < 16384);
-  }
-  fclose(file);
-
-  if (i > 5)
-  {
-    win_width = cpc_ram[load_address + i - 4] + (cpc_ram[load_address + i - 3] << 8);  // in bits
-    win_height = cpc_ram[load_address + i - 2];
-    if (((win_width + 7) >> 3) * win_height + 5 == i) // that's a WIN file !
-    {
-      width = win_width >> (2 - mode);
-      height = win_height;
-      is_win = 1;
-      columns = (win_width + 7) >> 3;
-      GFX2_Log(GFX2_DEBUG, ".WIN file detected len=%d (%d,%d) %dcols %02X %02X %02X %02X %02X\n",
-          i, width, height, columns,
-          cpc_ram[load_address + i - 5], cpc_ram[load_address + i - 4], cpc_ram[load_address + i - 3],
-          cpc_ram[load_address + i - 2], cpc_ram[load_address + i - 1]);
-    }
-    else
-    {
-      GFX2_Log(GFX2_DEBUG, ".SCR file. Data length %d\n", i);
-      if (load_address == 0x170)
-      {
-        // fichier iMPdraw v2
-        // http://orgams.wikidot.com/le-format-impdraw-v2
-        GFX2_Log(GFX2_DEBUG, "Detected \"%s\"\n", cpc_ram + load_address + 6);
-        mode = cpc_ram[load_address + 0x14] - 0x0e;
-        cpc_plus = cpc_ram[load_address + 0x3c];
-        GFX2_Log(GFX2_DEBUG, "Mode %d CPC %d\n", (int)mode, (int)cpc_plus);
-        for (addr = load_address + 0x1d; cpc_ram[addr] < 16; addr += 2)
-        {
-          GFX2_Log(GFX2_DEBUG, " R%d = &H%02x = %d\n", cpc_ram[addr], cpc_ram[addr+1], cpc_ram[addr+1]);
-          // see http://www.cpcwiki.eu/index.php/CRTC#The_6845_Registers
-          switch(cpc_ram[addr])
-          {
-            case 1:
-              columns = cpc_ram[addr+1] * 2;
-              break;
-            case 6:
-              height = cpc_ram[addr+1] * 8;
-              break;
-            case 12:
-              display_start = ((cpc_ram[addr+1] & 0x30) << 10) | ((cpc_ram[addr+1] & 0x03) << 9);
-              GFX2_Log(GFX2_DEBUG, "  display_start &H%04X\n", display_start);
-           }
-        }
-        snprintf(context->Comment, COMMENT_SIZE, "%s mode %d %s",
-                 cpc_ram + load_address + 7, mode, cpc_plus ? "CPC+" : "");
-        if (cpc_plus)
-        {
-          // palette at 0x801 (mode at 0x800 ?)
-          GFX2_LogHexDump(GFX2_DEBUG, "", cpc_ram, 0x800, 0x21);
-          cpc_plus_pal = cpc_ram + 0x801;
-        }
-        else
-        {
-          int j;
-          // palette at 0x7f00
-          GFX2_LogHexDump(GFX2_DEBUG, "", cpc_ram, 0x7f00, 16);
-          for (j = 0; j < 16; j++)
-            pal_data[12*j] = cpc_ram[0x7f00 + j];
-        }
-      }
-      else if (load_address == 0x200)
-      {
-        /* from HARLEY.SCR :
-        0800  00 = mode
-        0801-0810 palette (Firmware colors)
-        0811  21 47 08      LD HL,0847  ; OVERSCAN_REG_VALUES
-        0814  cd 36 08      CALL 0836 ; LOAD_CRTC_REGS
-        0817  3a 00 08      LD A,(0800) ; MODE
-        081a  cd 1c bd      CALL BD1C ; Set screen mode
-        081d  21 01 08      LD HL,0801  ; PALETTE
-        0820  af            XOR A
-            LOOP:
-        0821  4e            LD C,(HL)
-        0822  41            LD B,C
-        0823  f5            PUSH AF
-        0824  e5            PUSH HL
-        0825  cd 32 bc      CALL BC32   ; SET ink A to color B,C
-        0828  e1            POP HL
-        0829  f1            POP AF
-        082a  23            INC HL
-        082b  3c            INC A
-        082c  fe 10         CMP 10
-        082e  20 f1         JR NZ,0821  ; LOOP
-        0830  cd 18 bb      CALL BB18 ; Wait key press
-        0833  21 55 08      LD HL,0855  ; STANDARD_REG_VALUES
-            LOAD_CRTC_REGS:
-        0836  01 00 bc      LD BC,BC00
-            LOOP_CRTC:
-        0839  7e            LD A,(HL)
-        083a  a7            AND A
-        083b  c8            RET Z
-        083c  ed 79         OUT (C),A
-        083e  04            INC B
-        083f  23            INC HL
-        0840  7e            LD A,(HL)
-        0841  ed 79         OUT (C),A
-        0843  23            INC HL
-        0844  05            DEC B
-        0845  18 f2         JR 0839 ; LOOP_CRTC
-            OVERSCAN_REG_VALUES:
-        0847  01 30  02 32  06 22  07 23  0c 0d  0d 00  00 00
-            STANDARD_REG_VALUES:
-        0855  01 28  02 2e  06 19  07 1e  0c 30  00 00
-        */
-        int j;
-        static const byte CPC_Firmware_Colors[] = {
-          0x54, 0x44, 0x55, 0x5c, 0x58, 0x5d, 0x4c, 0x45, 0x4d,
-          0x56, 0x46, 0x57, 0x5e, 0x40, 0x5f, 0x4e, 0x47, 0x4f,
-          0x52, 0x42, 0x53, 0x5a, 0x59, 0x5b, 0x4a, 0x43, 0x4b };
-        mode = cpc_ram[0x800];
-        for (j = 0; j < 16; j++)
-          pal_data[12*j] = CPC_Firmware_Colors[cpc_ram[0x801 + j]];
-        addr = 0x847;
-        if (cpc_ram[0x80bb] == 1)
-          addr = 0x80bb;
-        for (; cpc_ram[addr] > 0 && cpc_ram[addr] < 16; addr += 2)
-        {
-          GFX2_Log(GFX2_DEBUG, " R%d = &H%02x = %d\n", cpc_ram[addr], cpc_ram[addr+1], cpc_ram[addr+1]);
-          // see http://www.cpcwiki.eu/index.php/CRTC#The_6845_Registers
-          switch(cpc_ram[addr])
-          {
-            case 1:
-              columns = cpc_ram[addr+1] * 2;
-              break;
-            case 6:
-              height = cpc_ram[addr+1] * 8;
-              break;
-            case 12:
-              display_start = (display_start & 0x00ff) | ((cpc_ram[addr+1] & 0x30) << 10) | ((cpc_ram[addr+1] & 0x03) << 9);
-              break;
-            case 13:
-              display_start = (display_start & 0xff00) | cpc_ram[addr+1];
-           }
-         }
-      }
-      if (i >= 30000)
-      {
-        height = 272; columns = 96;
-      }
-    }
-  }
-
-  switch (mode)
-  {
-    case 0:
-      width = columns * 2;
-      bpp = 4;
-      ratio = PIXEL_WIDE;
-      break;
-    case 1:
-      width = columns * 4;
-      bpp = 2;
-      ratio = PIXEL_SIMPLE;
-      break;
-    case 2:
-      width = columns * 8;
-      bpp = 1;
-      ratio = PIXEL_TALL;
-      break;
-    default:
-      return; // unsupported
-  }
-
-  if (Config.Clear_palette)
-    memset(context->Palette,0,sizeof(T_Palette));
-  // Setup the palette (amstrad hardware palette)
-  CPC_set_HW_palette(context->Palette + 0x40);
-
-  // Set the palette for this picture
-  if (cpc_plus_pal)
-  {
-    for (i = 0; i < 16; i++)
-    {
-      context->Palette[i].G = cpc_plus_pal[i*2 + 1] * 0x11;
-      context->Palette[i].R = (cpc_plus_pal[i*2] >> 4) * 0x11;
-      context->Palette[i].B = (cpc_plus_pal[i*2] & 15) * 0x11;
-    }
-  }
-  else
-  {
-    for (i = 0; i < 16; i++)
-      context->Palette[i] = context->Palette[pal_data[12*i]];
-  }
-
-  File_error = 0;
-  Pre_load(context, width, height, real_file_size, FORMAT_SCR, ratio, bpp);
-
-  if (!is_win)
-  {
-    // Standard resolution files have the 200 lines stored in block
-    // of 25 lines of 80 bytes = 2000 bytes every 2048 bytes.
-    // so there are 48 bytes unused every 2048 bytes...
-    for (y = 0; y < 8; y++)
-    {
-      addr = display_start + 0x800 * y;
-      if (y > 0 && (display_start & 0x7ff))
-      {
-        if (!GFX2_is_mem_filled_with(cpc_ram + (addr & 0xf800), 0, display_start & 0x7ff))
-          GFX2_LogHexDump(GFX2_DEBUG, "SCR1 ", cpc_ram,
-                          addr & 0xf800, display_start & 0x7ff);
-      }
-      addr += (height >> 3) * columns;
-      block_length = (height >> 3) * columns + (display_start & 0x7ff);
-      if (block_length <= 0x800)
-      {
-        block_length = 0x800 - block_length;
-        if (!GFX2_is_mem_filled_with(cpc_ram + addr, 0, block_length))
-          GFX2_LogHexDump(GFX2_DEBUG, "SCR2 ", cpc_ram,
-                          addr, block_length);
-      }
-      else
-      {
-        block_length = 0x1000 - block_length;
-        if (!GFX2_is_mem_filled_with(cpc_ram + addr + 0x4000, 0, block_length))
-          GFX2_LogHexDump(GFX2_DEBUG, "SCR2 ", cpc_ram,
-                          addr + 0x4000, block_length);
-      }
-    }
-    //for (j = 0; j < i; j += 2048)
-    //  GFX2_LogHexDump(GFX2_DEBUG, "SCR ", cpc_ram, load_address + j + 2000, 48);
-  }
-
-  GFX2_Log(GFX2_DEBUG, "  display_start &H%04X\n", display_start);
-  for (y = 0; y < height; y++)
-  {
-    const byte * line;
-
-    if (is_win)
-      addr = display_start + y * columns;
-    else
-    {
-      addr = display_start + ((y >> 3) * columns);
-      addr = (addr & 0xC7FF) | ((addr & 0x800) << 3);
-      addr += (y & 7) << 11;
-    }
-    //GFX2_Log(GFX2_DEBUG, "line#%d &H%04X\n", y, addr);
-    line = cpc_ram + addr;
-    x = 0;
-    for (i = 0; i < columns; i++)
-    {
-      byte pixels = line[i];
-      switch (mode)
-      {
-        case 0:
-          Set_pixel(context, x++, y, (pixels & 0x80) >> 7 | (pixels & 0x08) >> 2 | (pixels & 0x20) >> 3 | (pixels & 0x02) << 2);
-          Set_pixel(context, x++, y, (pixels & 0x40) >> 6 | (pixels & 0x04) >> 1 | (pixels & 0x10) >> 2 | (pixels & 0x01) << 3);
-          break;
-        case 1:
-          do {
-            // upper nibble is 4 lower color bits, lower nibble is 4 upper color bits
-            Set_pixel(context, x++, y, (pixels & 0x80) >> 7 | (pixels & 0x08) >> 2);
-            pixels <<= 1;
-          }
-          while ((x & 3) != 0);
-          break;
-        case 2:
-          do {
-            Set_pixel(context, x++, y, (pixels & 0x80) >> 7);
-            pixels <<= 1;
-          }
-          while ((x & 7) != 0);
-      }
-    }
-  }
-
-  free(cpc_ram);
-}
-
-/**
- * Save Amstrad SCR file
- *
- * guess mode from aspect ratio :
- * - normal pixels are mode 1
- * - wide pixels are mode 0
- * - tall pixels are mode 2
- *
- * Mode and palette are stored in a .PAL file.
- *
- * The picture color index should be 0-15,
- * The CPC Hardware palette is expected to be set (indexes 64 to 95)
- *
- * @todo Add possibility to set R9, R12, R13 values
- * @todo Add OCP packing support
- * @todo Add possibility to include AMSDOS header, with proper loading
- *       address guessed from r12/r13 values.
- */
-void Save_SCR(T_IO_Context * context)
-{
-  int i, j;
-  unsigned char* output;
-  unsigned long outsize = 0;
-  unsigned char r1 = 0;
-  int cpc_mode;
-  FILE* file;
-
-
-  switch(Pixel_ratio)
-  {
-    case PIXEL_WIDE:
-    case PIXEL_WIDE2:
-      cpc_mode = 0;
-      break;
-    case PIXEL_TALL:
-    case PIXEL_TALL2:
-    case PIXEL_TALL3:
-      cpc_mode = 2;
-      break;
-    default:
-      cpc_mode = 1;
-      break;
-  }
-
-  file = Open_file_write_with_alternate_ext(context, "pal");
-  if (file == NULL)
-    return;
-  if (!Write_byte(file, cpc_mode) || !Write_byte(file, 0) || !Write_byte(file, 0))
-  {
-    fclose(file);
-    return;
-  }
-  for (i = 0; i < 16; i++)
-  {
-    // search for the color in the HW palette (0x40-0x5F)
-    byte index = 0x40;
-    while ((index < 0x60) &&
-        !CPC_compare_colors(context->Palette + i, context->Palette + index))
-      index++;
-    if (index >= 0x60)
-    {
-      GFX2_Log(GFX2_WARNING, "Save_SCR() color #%i not found in CPC HW palette.\n", i);
-      index = 0x54 - i; // default
-    }
-    for (j = 0; j < 12; j++)  // write the same color for the 12 frames
-    {
-      Write_byte(file, index);
-    }
-  }
-  // border
-  for (j = 0; j < 12; j++)
-  {
-    Write_byte(file, 0x54); // black
-  }
-  // excluded inks
-  for (i = 0; i < 16; i++)
-  {
-    Write_byte(file, 0);
-  }
-  // protected inks
-  for (i = 0; i < 16; i++)
-  {
-    Write_byte(file, 0);
-  }
-  fclose(file);
-
-  output = raw2crtc(context, cpc_mode, 7, &outsize, &r1, 0x0C, 0);
-  GFX2_Log(GFX2_DEBUG, "Save_SCR() output=%p outsize=%lu r1=$%02X\n", output, outsize, r1);
-
-  if (output == NULL)
-    return;
-
-  file = Open_file_write(context);
-  if (file == NULL)
-    File_error = 1;
-  else
-  {
-    File_error = 0;
-    if (!Write_bytes(file, output, outsize))
-      File_error = 1;
-    fclose(file);
-  }
-  free (output);
-}
-
-/**
- * Test for GO1/GO2/KIT - Amstrad Plus Graphos
- *
- * This format is made of 3 files
- * .KIT hold the palette in "Kit4096" format. There are 16 colors each stored
- * as 12 bit RGB in RB0G order.
- * .GO1 and GO2 hold each half of the picture (top and bottom)
- * The file always cover the whole display of the Plus (196*272 or so)
- */
-void Test_GOS(T_IO_Context * context, FILE * file)
-{
-  FILE *file_oddeve;
-  unsigned long file_size = 0;
-
-  if (!CPC_check_AMSDOS(file, NULL, &file_size))
-    file_size = File_length_file(file);
-  if (file_size < 16383 || file_size > 16384) {
-    File_error = 1;
-    return;
-  }
-
-  file_oddeve = Open_file_read_with_alternate_ext(context, "GO2");
-  if (file_oddeve == NULL) {
-    File_error = 2;
-    return;
-  }
-  if (!CPC_check_AMSDOS(file_oddeve, NULL, &file_size))
-    file_size = File_length_file(file_oddeve);
-  fclose(file_oddeve);
-  if (file_size < 16383 || file_size > 16384) {
-    File_error = 3;
-    return;
-  }
-
-  File_error = 0;
-}
-
-
-/**
- * Load GO1/GO2/KIT - Amstrad CPC Plus Graphos
- */
-void Load_GOS(T_IO_Context* context)
-{
-  FILE *file;
-  unsigned long file_size;
-  int i;
-  int x, y;
-  byte * pixel_data;
-
-  if (!(file = Open_file_read(context)))
-  {
-      File_error = 1;
-      return;
-  }
-
-  if (CPC_check_AMSDOS(file, NULL, &file_size))
-    fseek(file, 128, SEEK_SET); // right after AMSDOS header
-  else
-    file_size = File_length_file(file);
-
-  context->Ratio = PIXEL_WIDE;
-  Pre_load(context, 192, 272, file_size, FORMAT_GOS, context->Ratio, 0);
-  context->Width = 192;
-  context->Height = 272;
-
-  // load pixels
-  pixel_data = GFX2_malloc(16384);
-  memset(pixel_data, 0, 16384);
-  Read_bytes(file, pixel_data, file_size);
-
-  i = 0;
-  for (y = 0; y < 168; y++) {
-    x = 0;
-    while (x < 192) {
-      byte pixels = pixel_data[i];
-      Set_pixel(context, x++, y, (pixels & 0x80) >> 7 | (pixels & 0x08) >> 2 | (pixels & 0x20) >> 3 | (pixels & 0x02) << 2);
-      Set_pixel(context, x++, y, (pixels & 0x40) >> 6 | (pixels & 0x04) >> 1 | (pixels & 0x10) >> 2 | (pixels & 0x01) << 3);
-      i++;
-    }
-
-    i += 0x800;
-    if (i > 0x3FFF) {
-      i -= 0x4000;
-    } else {
-      i -= 192 / 2;
-    }
-  }
-
-  fclose(file);
-
-  // load pixels from GO2
-  file = Open_file_read_with_alternate_ext(context, "GO2");
-  if (CPC_check_AMSDOS(file, NULL, &file_size))
-    fseek(file, 128, SEEK_SET); // right after AMSDOS header
-
-  Read_bytes(file, pixel_data, file_size);
-  i = 0;
-  for (y = 168; y < 272; y++) {
-    x = 0;
-    while (x < 192) {
-      byte pixels = pixel_data[i];
-      Set_pixel(context, x++, y, (pixels & 0x80) >> 7 | (pixels & 0x08) >> 2 | (pixels & 0x20) >> 3 | (pixels & 0x02) << 2);
-      Set_pixel(context, x++, y, (pixels & 0x40) >> 6 | (pixels & 0x04) >> 1 | (pixels & 0x10) >> 2 | (pixels & 0x01) << 3);
-      i++;
-    }
-
-    i += 0x800;
-    if (i > 0x3FFF) {
-      i -= 0x4000;
-    } else {
-      i -= 192 / 2;
-    }
-  }
-
-  fclose(file);
-
-  file = Open_file_read_with_alternate_ext(context, "KIT");
-  if (file == NULL) {
-    // There is no palette, but that's fine, we can still load the pixels
-    return;
-  }
-
-  if (CPC_check_AMSDOS(file, NULL, &file_size)) {
-    fseek(file, 128, SEEK_SET); // right after AMSDOS header
-  } else {
-    file_size = File_length_file(file);
-  }
-
-  if (Config.Clear_palette)
-    memset(context->Palette,0,sizeof(T_Palette));
-
-  File_error = 0;
-
-  if (file_size == 32)
-  {
-    for (i = 0; i < 16; i++)
-    {
-      uint16_t word;
-      if (!Read_word_le(file, &word))
-      {
-        File_error = 2;
-        return;
-      }
-
-      context->Palette[i].R = ((word >>  4) & 0xF) * 0x11;
-      context->Palette[i].G = ((word >>  8) & 0xF) * 0x11;
-      context->Palette[i].B = ((word >>  0) & 0xF) * 0x11;
-    }
-  }
-  else
-  {
-    // Setup the palette (amstrad hardware palette)
-    CPC_set_HW_palette(context->Palette + 0x40);
-    for (i = 0; i < 16; i++)
-    {
-      byte ink;
-      if (!Read_byte(file, &ink))
-      {
-        File_error = 2;
-        return;
-      }
-      context->Palette[i] = context->Palette[ink];
-    }
-  }
-
-  fclose(file);
-}
-
-/**
- * Test for CM5 - Amstrad CPC "Mode 5" picture
- *
- * This is a format designed by SyX.
- * There is one .GFX file in the usual amstrad format
- * and a .CM5 file with the palette, which varies over time.
- *
- * CM5 file is 2049 bytes, GFX is 18432 bytes.
- *
- * @todo check CM5 contains only valid values [0x40-0x5f]
- */
-void Test_CM5(T_IO_Context * context, FILE * file)
-{
-  // check cm5 file size == 2049 bytes
-  FILE *file_gfx;
-  long file_size;
-
-  File_error = 1;
-
-  file_size = File_length_file(file);
-  if (file_size != 2049)
-    return;
-
-  // check existence of a .GFX file with the same name
-  file_gfx = Open_file_read_with_alternate_ext(context, "gfx");
-  if (file_gfx == NULL)
-    return;
-  file_size = File_length_file(file_gfx);
-  fclose(file_gfx);
-  if (file_size != 18432)
-    return;
-
-  File_error = 0;
-}
-
-
-/**
- * Load Amstrad CPC "Mode 5" picture
- *
- * Only support 288x256 resolution as the Mode 5 Viewer app only handles this
- * single resoltion.
- */
-void Load_CM5(T_IO_Context* context)
-{
-  // Ensure "8bit" constraint mode is switched on
-  // Set palette to the CPC hardware colors
-  // Load the palette data to the 4 colorlayers
-  FILE *file;
-  byte value = 0;
-  int mod=0;
-  short line = 0;
-  int tx, ty;
-  // for preview :
-  byte ink0;
-  byte ink1[256];
-  byte ink2[256];
-  byte ink3[256*6];
-
-  if (!(file = Open_file_read(context)))
-  {
-      File_error = 1;
-      return;
-  }
-
-  Pre_load(context, 48*6, 256, 2049, FORMAT_CM5, PIXEL_SIMPLE, 0);
-
-  if (Config.Clear_palette)
-  {
-    memset(context->Palette,0,sizeof(T_Palette));
-    // setup colors 0,1,2,3 to see something in the thumbnail preview of layer 5
-    context->Palette[1].R = 60;
-    context->Palette[2].B = 60;
-    context->Palette[3].G = 60;
-  }
-
-  // Setup the palette (amstrad hardware palette)
-  CPC_set_HW_palette(context->Palette + 0x40);
-
-  First_color_in_palette = 64;
-
-  if (!Read_byte(file, &ink0))
-    File_error = 2;
-
-  // This forces the creation of 5 layers total :
-  // Needed because the "pixel" functions will seek layer 4
-  Set_loading_layer(context, 4);
-  // Now select layer 1 again
-  Set_loading_layer(context, 0);
-
-  if (context->Type == CONTEXT_MAIN_IMAGE)
-  {
-    Set_image_mode(context, IMAGE_MODE_MODE5);
-
-    // Fill layer with color we just read (Layer 1 - INK 0)
-    for(ty=0; tyHeight; ty++)
-      for(tx=0; txWidth; tx++)
-        Set_pixel(context, tx, ty, ink0);
-  }
-
-  while(Read_byte(file, &value))
-  {
-    switch(mod)
-    {
-      case 0:
-        // This is color for layer 2 - INK 1
-        Set_loading_layer(context, 1);
-        for(tx=0; txWidth; tx++)
-          Set_pixel(context, tx, line, value);
-        ink1[line] = value;
-        break;
-      case 1:
-        // This is color for layer 3 - INK 2
-        Set_loading_layer(context, 2);
-        for(tx=0; txWidth; tx++)
-          Set_pixel(context, tx, line, value);
-        ink2[line] = value;
-        break;
-      default:
-        // This is color for a block in layer 4 - INK 3
-        Set_loading_layer(context, 3);
-        for(tx=(mod-2)*48; tx<(mod-1)*48; tx++)
-          Set_pixel(context, tx, line, value);
-        ink3[line*6+(mod-2)] = value;
-        break;
-    }
-    mod++;
-    if (mod > 7)
-    {
-      mod = 0;
-      line++;
-    }
-  }
-
-  fclose(file);
-
-  // Load the pixeldata to the 5th layer
-  file = Open_file_read_with_alternate_ext(context, "gfx");
-  if (file == NULL)
-  {
-    File_error = 1;
-    return;
-  }
-  Set_loading_layer(context, 4);
-
-  if (context->Type == CONTEXT_PREVIEW)
-    for (ty = 0; ty < 256; ty++)
-      for (tx = 0; tx < 48*6; )
-      {
-        Read_byte(file, &value);
-        for (mod = 0; mod < 4; mod++, tx++, value <<= 1)
-        {
-          switch(3 ^ (((value&0x80) >> 7) | ((value&0x8)>>2)))  // INK
-          {
-            case 0:
-              Set_pixel(context, tx, ty, ink0);
-              break;
-            case 1:
-              Set_pixel(context, tx, ty, ink1[ty]);
-              break;
-            case 2:
-              Set_pixel(context, tx, ty, ink2[ty]);
-              break;
-            default:
-              Set_pixel(context, tx, ty, ink3[ty*6+(tx/48)]);
-          }
-        }
-      }
-  else
-    for (ty = 0; ty < 256; ty++)
-      for (tx = 0; tx < 48*6; )
-      {
-        Read_byte(file, &value);
-        Set_pixel(context, tx++, ty, 3 ^ (((value&0x80) >> 7) | ((value&0x8)>>2)));
-        Set_pixel(context, tx++, ty, 3 ^ (((value&0x40) >> 6) | ((value&0x4)>>1)));
-        Set_pixel(context, tx++, ty, 3 ^ (((value&0x20) >> 5) | ((value&0x2)>>0)));
-        Set_pixel(context, tx++, ty, 3 ^ (((value&0x10) >> 4) | ((value&0x1)<<1)));
-      }
-
-  fclose(file);
-
-}
-
-
-void Save_CM5(T_IO_Context* context)
-{
-  FILE* file;
-  int tx, ty;
-
-  // TODO: Check picture has 5 layers
-  // TODO: Check the constraints on the layers
-  // Layer 1 : 1 color Only
-  // Layer 2 and 3 : 1 color/line
-  // Layer 4 : 1 color / 48x1 block
-  // TODO: handle filesize
-
-  if (!(file = Open_file_write(context)))
-  {
-    File_error = 1;
-    return;
-  }
-  setvbuf(file, NULL, _IOFBF, 64*1024);
-
-  // Write layer 0
-  Set_saving_layer(context, 0);
-  Write_byte(file, Get_pixel(context, 0, 0));
-  for(ty = 0; ty < 256; ty++)
-  {
-    Set_saving_layer(context, 1);
-    Write_byte(file, Get_pixel(context, 0, ty));
-    Set_saving_layer(context, 2);
-    Write_byte(file, Get_pixel(context, 0, ty));
-    Set_saving_layer(context, 3);
-    for(tx = 0; tx < 6; tx++)
-    {
-      Write_byte(file, Get_pixel(context, tx*48, ty));
-    }
-  }
-
-  fclose(file);
-
-  // Now the pixeldata
-  if (!(file = Open_file_write_with_alternate_ext(context, "gfx")))
-  {
-    File_error = 2;
-    return;
-  }
-  setvbuf(file, NULL, _IOFBF, 64*1024);
-
-  Set_saving_layer(context, 4);
-
-  for (ty = 0; ty < 256; ty++)
-  {
-    for (tx = 0; tx < 48*6; tx+=4)
-    {
-      byte code = 0;
-      byte pixel;
-
-      pixel = 3-Get_pixel(context, tx+3, ty);
-      code |= (pixel&2)>>1 | ((pixel & 1)<<4);
-      pixel = 3-Get_pixel(context, tx+2, ty);
-      code |= ((pixel&2)<<0) | ((pixel & 1)<<5);
-      pixel = 3-Get_pixel(context, tx+1, ty);
-      code |= ((pixel&2)<<1) | ((pixel & 1)<<6);
-      pixel = 3-Get_pixel(context, tx, ty);
-      code |= ((pixel&2)<<2) | ((pixel & 1)<<7);
-      Write_byte(file, code);
-    }
-  }
-
-  fclose(file);
-  File_error = 0;
-
-}
-
-
-/* Amstrad CPC 'PPH' for Perfect Pix.
-// This is a format designed by Rhino.
-// There are 3 modes:
-// - Mode 'R': 1:1 pixels, 16 colors from the CPC 27 color palette.
-//   (this is implemented on CPC as two pictures with wide pixels, the "odd" one
-//   being shifted half a pixel to the right), and flipping)
-// - Mode 'B0': wide pixels, up to 126 out of 378 colors.
-//   (this is implemented as two pictures with wide pixels, sharing the same 16
-//   color palette, and flipping)
-// - Mode 'B1': 1:1 pixels, 1 fixed color, up to 34 palettes of 9 colors
-//   (actually 4 colors + flipping)
-//
-// - The standard CPC formats can also be encapsulated into a PPH file.
-//
-// http://www.pouet.net/prod.php?which=67770#c766959
-*/
-void Test_PPH(T_IO_Context * context, FILE * file)
-{
-  FILE *file_oddeve;
-  byte buffer[6];
-  unsigned long file_size;
-  unsigned int w, h;
-  unsigned int expected;
-
-  File_error = 1;
-
-  // First check file size is large enough to hold the header
-  file_size = File_length_file(file);
-  if (file_size < 11) {
-    File_error = 1;
-    return;
-  }
-
-  // File is large enough for the header, now check if the data makes some sense
-  if (!Read_bytes(file, buffer, 6))
-    return;
-  if (buffer[0] > 5) {
-    // Unknown mode
-    File_error = 2;
-    return;
-  }
-
-  w = buffer[1] | (buffer[2] << 8);
-  if (w < 2 || w > 384) {
-    // Invalid width
-    File_error = 3;
-    return;
-  }
-
-  h = buffer[3] | (buffer[4] << 8);
-  if (h < 1 || h > 272) {
-    // Invalid height
-    File_error = 4;
-    return;
-  }
-
-  if (buffer[5] < 1 || buffer[5] > 28)
-  {
-    // Invalid palettes count
-    File_error = 5;
-    return;
-  }
-  expected = 6; // Size of header
-  switch(buffer[0])
-  {
-    case 0:
-    case 3:
-    case 4:
-      // Palette size should be 16 bytes, only 1 palette.
-      if (buffer[5] != 1) {
-        File_error = 7;
-        return;
-      }
-      expected += 16;
-      break;
-
-    case 1:
-    case 5:
-      expected += buffer[5] * 5 - 1;
-      break;
-
-    case 2:
-      // Palette size should be 2 bytes
-      if (buffer[5] != 1) {
-        File_error = 7;
-        return;
-      }
-      expected += 2;
-      break;
-  }
-
-  if (file_size != expected)
-  {
-    File_error = 6;
-    return;
-  }
-
-  // check existence of .ODD/.EVE files with the same name
-  // and the right size
-  expected = w * h / 4;
-  file_oddeve = Open_file_read_with_alternate_ext(context, "odd");
-  if (file_oddeve == NULL)
-    return;
-  file_size = File_length_file(file_oddeve);
-  fclose (file_oddeve);
-  if (file_size != expected)
-  {
-    File_error = 8;
-    return;
-  }
-  file_oddeve = Open_file_read_with_alternate_ext(context, "eve");
-  if (file_oddeve == NULL)
-    return;
-  file_size = File_length_file(file_oddeve);
-  fclose(file_oddeve);
-  if (file_size != expected)
-  {
-    File_error = 8;
-    return;
-  }
-  File_error = 0;
-}
-
-
-static uint8_t pph_blend(uint8_t a, uint8_t b)
-{
-	uint32_t h,l;
-	if (a > b) { h = a; l = b; }
-	else       { h = b; l = a; }
-
-	return (23 * h + 9 * l) / 32;
-}
-
-
-void Load_PPH(T_IO_Context* context)
-{
-  FILE *file;
-  FILE *feven;
-
-  // Read in the header
-  uint8_t mode;
-  uint16_t width;
-  uint16_t height;
-  uint8_t npal;
-  int i,j;
-  uint8_t a,b,c,d;
-  int file_size;
-  uint8_t pl[16];
-
-  static const T_Components CPCPAL[27] =
-  {
-      { 0x00, 0x02, 0x01 }, { 0x00, 0x02, 0x6B }, { 0x0C, 0x02, 0xF4 },
-      { 0x6C, 0x02, 0x01 }, { 0x69, 0x02, 0x68 }, { 0x6C, 0x02, 0xF2 },
-      { 0xF3, 0x05, 0x06 }, { 0xF0, 0x02, 0x68 }, { 0xF3, 0x02, 0xF4 },
-      { 0x02, 0x78, 0x01 }, { 0x00, 0x78, 0x68 }, { 0x0C, 0x7B, 0xF4 },
-      { 0x6E, 0x7B, 0x01 }, { 0x6E, 0x7D, 0x6B }, { 0x6E, 0x7B, 0xF6 },
-      { 0xF3, 0x7D, 0x0D }, { 0xF3, 0x7D, 0x6B }, { 0xFA, 0x80, 0xF9 },
-      { 0x02, 0xF0, 0x01 }, { 0x00, 0xF3, 0x6B }, { 0x0F, 0xF3, 0xF2 },
-      { 0x71, 0xF5, 0x04 }, { 0x71, 0xF3, 0x6B }, { 0x71, 0xF3, 0xF4 },
-      { 0xF3, 0xF3, 0x0D }, { 0xF3, 0xF3, 0x6D }, { 0xFF, 0xF3, 0xF9 }
-  };
-
-  if (!(file = Open_file_read(context)))
-  {
-      File_error = 1;
-      return;
-  }
-
-  file_size=File_length_file(file);
-
-  Read_byte(file, &mode);
-  Read_word_le(file, &width);
-  Read_word_le(file, &height);
-  Read_byte(file, &npal);
-
-  if (npal > 16)
-      npal = 16;
-
-  // Switch to the proper aspect ratio
-  switch (mode)
-  {
-      case 0:
-      case 4:
-        context->Ratio = PIXEL_WIDE;
-        width /= 2;
-        break;
-
-      case 2:
-        context->Ratio = PIXEL_TALL;
-        break;
-
-      case 1:
-      case 5:
-      case 3:
-        context->Ratio = PIXEL_SIMPLE;
-        break;
-  }
-
-  Pre_load(context, width, height, file_size, FORMAT_PPH, context->Ratio, 0);
-
-  context->Width = width;
-  context->Height = height;
-
-  // First of all, detect the mode
-  // 0, 1, 2 > Load as with SCR files?
-  // R(3)    > Load as single layer, square pixels, 16 colors
-  // B0(4)   > Load as single layer, wide pixels, expand palette with colorcycling
-  // B1(5)   > Load as ???
-  //           Maybe special mode similar to mode5, with 2 layers + auto-flicker?
-
-  switch (mode)
-  {
-      case 0:
-      case 3: // R
-          // 16-color palette
-          for (i = 0; i < 16; i++)
-          {
-              uint8_t color;
-              Read_byte(file, &color);
-              context->Palette[i] = CPCPAL[color];
-          }
-          break;
-
-      case 1:
-      case 5: // B1
-      {
-          // Single or multiple 4-color palettes
-          uint8_t base[4];
-          for (j = 0; j < npal; j++)
-          {
-            for (i = 0; i < 4; i++)
-            {
-              Read_byte(file,&base[i]);
-            }
-            for (i = 0; i < 16; i++)
-            {
-              context->Palette[i + 16*j].R = pph_blend(
-                  CPCPAL[base[i & 3]].R, CPCPAL[base[i >> 2]].R);
-              context->Palette[i + 16*j].G = pph_blend(
-                  CPCPAL[base[i & 3]].G, CPCPAL[base[i >> 2]].G);
-              context->Palette[i + 16*j].B = pph_blend(
-                  CPCPAL[base[i & 3]].B, CPCPAL[base[i >> 2]].B);
-            }
-            // TODO this byte marks where this palette stops being used and the
-            // next starts. We must handle this!
-            Read_byte(file,&pl[j]);
-          }
-          pl[npal - 1] = 255;
-          break;
-      }
-
-      case 2:
-          // Single 2-color palette
-          break;
-
-      case 4: // B0
-      {
-          // Single 16-color palette + flipping, need to expand palette and
-          // setup colorcycling ranges.
-          uint8_t base[16];
-          for (i = 0; i < 16; i++)
-          {
-              Read_byte(file,&base[i]);
-          }
-
-          for (i = 0; i < 256; i++)
-          {
-              context->Palette[i].R = pph_blend(
-                  CPCPAL[base[i & 15]].R, CPCPAL[base[i >> 4]].R);
-              context->Palette[i].G = pph_blend(
-                  CPCPAL[base[i & 15]].G, CPCPAL[base[i >> 4]].G);
-              context->Palette[i].B = pph_blend(
-                  CPCPAL[base[i & 15]].B, CPCPAL[base[i >> 4]].B);
-          }
-      }
-      break;
-  }
-
-  fclose(file);
-
-  // Load the picture data
-  // There are two pages, each storing bytes in the CPC vram format but lines in
-  // linear order.
-  file = Open_file_read_with_alternate_ext(context, "odd");
-  if (file == NULL)
-  {
-    File_error = 3;
-    return;
-  }
-  feven = Open_file_read_with_alternate_ext(context, "eve");
-  if (feven == NULL)
-  {
-    File_error = 4;
-    fclose(file);
-    return;
-  }
-
-  c = 0;
-  d = 0;
-
-  for (j = 0; j < height; j++)
-  {
-      for (i = 0; i < width;)
-      {
-          uint8_t even, odd;
-          Read_byte(feven, &even);
-          Read_byte(file, &odd);
-
-          switch (mode)
-          {
-              case 4:
-                a = ((even & 0x02) << 2) | ((even & 0x08) >> 2)
-                  | ((even & 0x20) >> 3) | ((even & 0x80) >> 7);
-                a <<= 4;
-                a |= ((odd & 0x02) << 2) | (( odd & 0x08) >> 2)
-                  | (( odd & 0x20) >> 3) | (( odd & 0x80) >> 7);
-
-                b = ((even & 0x01) << 3) | ((even & 0x04) >> 1)
-                  | ((even & 0x10) >> 2) | ((even & 0x40) >> 6);
-                b <<= 4;
-                b |= ((odd & 0x01) << 3) | (( odd & 0x04) >> 1)
-                  | (( odd & 0x10) >> 2) | (( odd & 0x40) >> 6);
-
-                Set_pixel(context, i++, j, a);
-                Set_pixel(context, i++, j, b);
-                break;
-
-              case 3:
-                a = ((even & 0x02) << 2) | ((even & 0x08) >> 2)
-                  | ((even & 0x20) >> 3) | ((even & 0x80) >> 7);
-                b = (( odd & 0x02) << 2) | (( odd & 0x08) >> 2)
-                  | (( odd & 0x20) >> 3) | (( odd & 0x80) >> 7);
-                c = ((even & 0x01) << 3) | ((even & 0x04) >> 1)
-                  | ((even & 0x10) >> 2) | ((even & 0x40) >> 6);
-                d = (( odd & 0x01) << 3) | (( odd & 0x04) >> 1)
-                  | (( odd & 0x10) >> 2) | (( odd & 0x40) >> 6);
-                Set_pixel(context, i++, j, j & 1 ? b : a);
-                Set_pixel(context, i++, j, j & 1 ? a : b);
-                Set_pixel(context, i++, j, j & 1 ? d : c);
-                Set_pixel(context, i++, j, j & 1 ? c : d);
-                break;
-
-              case 5:
-                if (d >= pl[c])
-                {
-                    d = 0;
-                    c++;
-                }
-                a = ((even & 0x80) >> 6) | ((even & 0x08) >> 3);
-                b = (( odd & 0x80) >> 6) | (( odd & 0x08) >> 3);
-                Set_pixel(context, i++, j, a + (b << 2) + c * 16);
-                a = ((even & 0x40) >> 5) | ((even & 0x04) >> 2);
-                b = (( odd & 0x40) >> 5) | (( odd & 0x04) >> 2);
-                Set_pixel(context, i++, j, a + (b << 2) + c * 16);
-                a = ((even & 0x20) >> 4) | ((even & 0x02) >> 1);
-                b = (( odd & 0x20) >> 4) | (( odd & 0x02) >> 1);
-                Set_pixel(context, i++, j, a + (b << 2) + c * 16);
-                a = ((even & 0x10) >> 3) | ((even & 0x01) >> 0);
-                b = (( odd & 0x10) >> 3) | (( odd & 0x01) >> 0);
-                Set_pixel(context, i++, j, a + (b << 2) + c * 16);
-
-                break;
-
-              default:
-                File_error = 2;
-                return;
-          }
-
-      }
-      d++;
-  }
-  fclose(file);
-  fclose(feven);
-
-  File_error = 0;
-}
-
-void Save_PPH(T_IO_Context* context)
-{
-  (void)context; // unused
-    // TODO
-
-    // Detect mode
-    // Wide pixels => B0 (4)
-    // Square pixels:
-    // - 16 colors used => R
-    // - more colors used => B1 (if <16 colors per line)
-
-    // Check palette
-    // B0: use diagonal: 0, 17, 34, ... (assume the other are mixes)
-    // R: use 16 used colors (or 16 first?)
-    // B1: find the 16 colors used in a line? Or assume they are in-order already?
-}
-
-
 /////////////////////////////////// FLI/FLC /////////////////////////////////
 typedef struct {
   dword size;          /* Size of FLIC including this header */