diff --git a/share/grafx2/skins/unicode_0410-044F.png b/share/grafx2/skins/unicode_0410-044F.png
new file mode 100644
index 00000000..c5b70d5c
Binary files /dev/null and b/share/grafx2/skins/unicode_0410-044F.png differ
diff --git a/src/buttons.c b/src/buttons.c
index 3fc89f10..69e169c9 100644
--- a/src/buttons.c
+++ b/src/buttons.c
@@ -1459,7 +1459,7 @@ void Button_Skins(void)
         T_Fileselector_item* fontName;
         selected_font = Window_attribute2; // Get the index of the chosen font.
         fontName = Get_item_by_index(&Font_files_list,selected_font);
-        new_font = Load_font(fontName->Full_name);
+        new_font = Load_font(fontName->Full_name, 1);
         if (new_font)
         {
           free(Menu_font);
@@ -1498,7 +1498,7 @@ void Button_Skins(void)
       Set_current_skin(skinsdir, gfx);
     }
     // (Re-)load the selected font
-    new_font = Load_font(Get_item_by_index(&Font_files_list,selected_font)->Full_name);
+    new_font = Load_font(Get_item_by_index(&Font_files_list,selected_font)->Full_name, 1);
     if (new_font)
     {
       const char * fname;
diff --git a/src/global.h b/src/global.h
index 6b669065..8ddbd191 100644
--- a/src/global.h
+++ b/src/global.h
@@ -646,6 +646,9 @@ GFX2_GLOBAL byte Resolution_in_command_line;
 /// Pointer to the font selected for menus.
 GFX2_GLOBAL byte * Menu_font;
 
+/// additional fonts for unicode characters
+GFX2_GLOBAL T_Unicode_Font * Unicode_fonts;
+
 /// Pointer to the current active skin.
 GFX2_GLOBAL T_Gui_skin * Gfx;
 
diff --git a/src/init.c b/src/init.c
index 4b34a50c..a300227b 100644
--- a/src/init.c
+++ b/src/init.c
@@ -701,27 +701,36 @@ T_Gui_skin * Load_graphics(const char * skin_file, T_Gradient_array *gradients)
 
 // ---- font loading -----
 
-byte Parse_font(SDL_Surface * image, byte * font)
+static byte * Parse_font(SDL_Surface * image, int is_main)
 {
+  byte * font;
   int character;
   byte color;
   int x, y;
   int chars_per_line;
+  int character_count;
   
   // Check image size
   if (image->w % 8)
   {
     sprintf(Gui_loading_error_message, "Error in font file: Image width is not a multiple of 8.\n");
-    return 1;
+    return NULL;
   }
-  if (image->w * image->h < 8*8*256)
+  character_count = (image->w * image->h) / (8*8);
+  if (is_main && character_count < 256)
   {
     sprintf(Gui_loading_error_message, "Error in font file: Image is too small to be a 256-character 8x8 font.\n");
-    return 1;
+    return NULL;
+  }
+  font = (byte *)malloc(8*8*character_count);
+  if (font == NULL)
+  {
+    sprintf(Gui_loading_error_message, "Not enough memory to read font file\n");
+    return NULL;
   }
   chars_per_line = image->w/8;
 
-  for (character=0; character < 256; character++)
+  for (character=0; character < character_count; character++)
   {
     for (y=0; y<8; y++)
     {
@@ -732,19 +741,20 @@ byte Parse_font(SDL_Surface * image, byte * font)
         if (color > 1)
         {
           sprintf(Gui_loading_error_message, "Error in font file: Only colors 0 and 1 can be used for the font.\n");
-          return 1;
+          free(font);
+          return NULL;
         }
         // Put it in font. 0 = BG, 1 = FG.
         font[character*64 + y*8 + x]=color;
       }
     }
   }
-  return 0;
+  return font;
 }
 
-byte * Load_font(const char * font_name)
+byte * Load_font(const char * font_name, int is_main)
 {
-  byte * font;
+  byte * font = NULL;
   char filename[MAX_PATH_CHARACTERS];
   SDL_Surface * image;
 
@@ -754,13 +764,6 @@ byte * Load_font(const char * font_name)
     return NULL;
   }
 
-  font = (byte *)malloc(8*8*256);
-  if (font == NULL)
-  {
-    sprintf(Gui_loading_error_message, "Not enough memory to read font file\n");
-    return NULL;
-  }
-  
   // Read the file containing the image
   sprintf(filename,"%s" SKINS_SUBDIRECTORY "%s%s", Data_directory, PATH_SEPARATOR, font_name);
   
@@ -768,19 +771,41 @@ byte * Load_font(const char * font_name)
   if (!image)
   {
     sprintf(Gui_loading_error_message, "Unable to load the skin image (missing? not an image file?)\n");
-    free(font);
-    return NULL;
-  }
-  if (Parse_font(image, font))
-  {
-    SDL_FreeSurface(image);
-    free(font);
     return NULL;
   }
+  font = Parse_font(image, is_main);
   SDL_FreeSurface(image);
   return font;
 }
 
+static void Load_Unicode_font(const char * filename)
+{
+  T_Unicode_Font * ufont;
+  byte * font;
+  unsigned int first, last;
+
+  if (sscanf(filename, "unicode_%04X-%04X.png", &first, &last) == 2)
+  {
+    font = Load_font(filename, 0);
+    if (font)
+    {
+      ufont = malloc(sizeof(T_Unicode_Font));
+      ufont->FirstChar = first;
+      ufont->LastChar = last;
+      ufont->FontData = font;
+      ufont->Next = Unicode_fonts;
+      Unicode_fonts = ufont;
+    }
+  }
+  else
+    Warning("Could not parse filename");
+}
+
+void Load_Unicode_fonts(void)
+{
+  // TODO : for each unicode*.png file in skin directory
+  Load_Unicode_font("unicode_0410-044F.png");
+}
 
 // Initialisation des boutons:
 
diff --git a/src/init.h b/src/init.h
index 14714cac..eafcc214 100644
--- a/src/init.h
+++ b/src/init.h
@@ -47,4 +47,7 @@ extern char Gui_loading_error_message[512];
 /// successful.
 /// If an error is encountered, it frees what needs it, prints an error message
 /// in ::Gui_loading_error_message, and returns NULL.
-byte * Load_font(const char * font_name);
+byte * Load_font(const char * font_name, int is_main);
+
+/// Load fonts for additional Unicode characters
+void Load_Unicode_fonts(void);
diff --git a/src/main.c b/src/main.c
index 3d96e27d..4efa10ad 100644
--- a/src/main.c
+++ b/src/main.c
@@ -745,12 +745,13 @@ int Init_program(int argc,char * argv[])
   Copy_preset_sieve(0);
 
   // Font
-  if (!(Menu_font=Load_font(Config.Font_file)))
-    if (!(Menu_font=Load_font(DEFAULT_FONT_FILENAME)))
+  if (!(Menu_font=Load_font(Config.Font_file, 1)))
+    if (!(Menu_font=Load_font(DEFAULT_FONT_FILENAME, 1)))
       {
         printf("Unable to open the default font file: %s\n", DEFAULT_FONT_FILENAME);
         Error(ERROR_GUI_MISSING);
       }
+  Load_Unicode_fonts();
 
   memcpy(Main.palette, Gfx->Default_palette, sizeof(T_Palette));
 
@@ -993,6 +994,16 @@ void Program_shutdown(void)
   free(Gfx);
   Gfx=NULL;
 
+  free(Menu_font);
+  Menu_font = NULL;
+  while (Unicode_fonts != NULL)
+  {
+    T_Unicode_Font * ufont = Unicode_fonts->Next;
+    free(Unicode_fonts->FontData);
+    free(Unicode_fonts);
+    Unicode_fonts = ufont;
+  }
+
   // On prend bien soin de passer dans le répertoire initial:
   if (chdir(Initial_directory)!=-1)
   {
diff --git a/src/struct.h b/src/struct.h
index e85d4f81..1e6177ba 100644
--- a/src/struct.h
+++ b/src/struct.h
@@ -549,7 +549,7 @@ typedef struct T_Selector_settings
   char  Directory[MAX_PATH_CHARACTERS]; ///< Directory currently browsed
 } T_Selector_settings;
 
-// structure for Main or Spare page global data
+/// structure for Main or Spare page global data
 typedef struct
 {
   /// Palette
@@ -618,4 +618,12 @@ typedef struct
   T_List_of_pages * backups;
 } T_Document;
 
+typedef struct T_Unicode_Font
+{
+  struct T_Unicode_Font * Next;
+  dword FirstChar;
+  dword LastChar;
+  byte * FontData;
+} T_Unicode_Font;
+
 #endif
diff --git a/src/unicode.c b/src/unicode.c
new file mode 100644
index 00000000..3517d7b6
--- /dev/null
+++ b/src/unicode.c
@@ -0,0 +1,81 @@
+/* vim:expandtab:ts=2 sw=2:
+*/
+/*  Grafx2 - The Ultimate 256-color bitmap paint program
+
+    Copyright 2018 Thomas Bernard
+    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 
+*/
+
+#include 
+#include 
+
+#include "unicode.h"
+
+size_t Unicode_strlen(const word * str)
+{
+  size_t len;
+
+  len = 0;
+  while(str[len] != 0)
+    len++;
+  return len;
+}
+
+/// equivalent of strdup() for our Unicode strings
+word * Unicode_strdup(const word * str)
+{
+  size_t byte_size;
+  word * new_str;
+
+  byte_size = Unicode_strlen(str) * 2 + 2;
+  new_str = malloc(byte_size);
+  if (new_str != NULL)
+    memcpy(new_str, str, byte_size);
+  return new_str;
+}
+
+/// Compare an unicode string with a regular Latin1 string
+int Unicode_char_strcmp(const word * s1, const char * s2)
+{
+  const byte * str2 = (const byte *)s2;
+
+  while (*s1 == *str2)
+  {
+    if (*s1 == 0) return 0;
+    s1++;
+    str2++;
+  }
+  return (*s1 > *str2) ? 1 : -1;
+}
+
+/// Copy a regular Latin1 string to an unicode string
+void Unicode_char_strlcpy(word * dst, const char * src, size_t len)
+{
+  const byte * s = (const byte *)src;
+
+  if (len == 0)
+    return;
+  while (len > 1)
+  {
+    *dst = *s;
+    if (*s == '\0')
+      return;
+    dst++;
+    s++;
+    len--;
+  }
+  *dst = 0;
+}
diff --git a/src/unicode.h b/src/unicode.h
new file mode 100644
index 00000000..c3948904
--- /dev/null
+++ b/src/unicode.h
@@ -0,0 +1,39 @@
+/* vim:expandtab:ts=2 sw=2:
+*/
+/*  Grafx2 - The Ultimate 256-color bitmap paint program
+
+    Copyright 2018 Thomas Bernard
+    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 
+*/
+#ifndef UNICODE_H_INCLUDED
+#define UNICODE_H_INCLUDED
+
+#include "struct.h"
+
+/// equivalent of strlen() for out Unicode strings
+/// return the number of characters (words), so there is twice as much bytes
+size_t Unicode_strlen(const word * str);
+
+/// equivalent of strdup() for our Unicode strings
+word * Unicode_strdup(const word * str);
+
+/// Compare an unicode string with a regular Latin1 string
+int Unicode_char_strcmp(const word * s1, const char * s2);
+
+/// Copy a regular Latin1 string to an unicode string
+void Unicode_char_strlcpy(word * dst, const char * src, size_t len);
+
+#endif
diff --git a/src/windows.c b/src/windows.c
index 60d08bb2..60540bbb 100644
--- a/src/windows.c
+++ b/src/windows.c
@@ -708,13 +708,25 @@ void Print_general(short x,short y,const char * str,byte text_color,byte backgro
 }
 
 /// Draws a char in a window
-void Print_char_in_window(short x_pos,short y_pos,const unsigned char c,byte text_color,byte background_color)
+void Print_char_in_window(short x_pos, short y_pos, unsigned int c,byte text_color,byte background_color)
 {
   short x,y;
-  byte *pixel;
+  const byte *pixel;
   // Premier pixel du caractère
-  pixel=Menu_font + (c<<6);
-
+  if (c < 256)
+    pixel=Menu_font + (c<<6);
+  else
+  {
+    T_Unicode_Font * ufont;
+    pixel=Menu_font + (1<<6); // dummy character
+    for (ufont = Unicode_fonts; ufont != NULL; ufont = ufont->Next)
+      if (ufont->FirstChar <= c && c <= ufont->LastChar)
+      {
+        pixel = ufont->FontData + ((c - ufont->FirstChar) << 6);
+        break;
+      }
+  }
+  
   for (y=0;y<8;y++)
     for (x=0;x<8;x++)
       Pixel_in_window(x_pos+x, y_pos+y,
@@ -739,16 +751,31 @@ void Print_in_window_limited(short x,short y,const char * str,byte size,byte tex
 void Print_in_window(short x,short y,const char * str,byte text_color,byte background_color)
 {
   short x_pos = x;
-  int index;
+  const unsigned char * p = (const unsigned char *)str;
 
-  for (index=0;str[index]!='\0';index++)
+  while (*p !='\0')
   {
-    Print_char_in_window(x,y,str[index],text_color,background_color);
+    Print_char_in_window(x,y,*p++,text_color,background_color);
     x+=8;
   }
-  Update_window_area(x_pos,y,8*strlen(str),8);
+  Update_window_area(x_pos,y,x-x_pos,8);
 }
 
+/// Draws a string in a window
+void Print_in_window_utf16(short x,short y,const word * str,byte text_color,byte background_color)
+{
+  short x_pos = x;
+  const word * p = str;
+
+  while (*p != 0)
+  {
+    Print_char_in_window(x,y,*p++,text_color,background_color);
+    x+=8;
+  }
+  Update_window_area(x_pos,y,x-x_pos,8);
+}
+
+
 // Draws a string in the menu's status bar
 void Print_in_menu(const char * str, short position)
 {
diff --git a/src/windows.h b/src/windows.h
index 0b2ea718..91569587 100644
--- a/src/windows.h
+++ b/src/windows.h
@@ -67,8 +67,9 @@ word Palette_cells_Y(void);
 
 void Print_general(short x,short y,const char * str,byte text_color,byte background_color);
 void Print_in_window(short x,short y,const char * str,byte text_color,byte background_color);
+void Print_in_window_utf16(short x,short y,const word * str,byte text_color,byte background_color);
 void Print_in_window_limited(short x,short y,const char * str,byte size,byte text_color,byte background_color);
-void Print_char_in_window(short x_pos,short y_pos,const unsigned char c,byte text_color,byte background_color);
+void Print_char_in_window(short x_pos,short y_pos, unsigned int c,byte text_color,byte background_color);
 void Print_in_menu(const char * str, short position);
 void Print_coordinates(void);
 void Print_filename(void);