Load from clipboard

This commit is contained in:
Thomas Bernard 2018-12-19 13:10:07 +01:00
parent b706566f57
commit 3876bb03e1
3 changed files with 297 additions and 81 deletions

View File

@ -154,6 +154,7 @@ enum FILE_FORMATS
FORMAT_MOTO, ///< Thomson MO/TO computers pictures
FORMAT_HGR, ///< Apple II HGR and DHGR
FORMAT_MISC, ///< Must be last of enum: others formats recognized by SDL_image (or recoil)
FORMAT_CLIPBOARD ///< To load/save from/to Clipboard
};
/// Default format for 'save as'

View File

@ -1613,6 +1613,7 @@ byte Button_Load_or_Save(T_Selector_settings *settings, byte load, T_IO_Context
char initial_comment[COMMENT_SIZE+1];
short window_shortcut;
const char * directory_to_change_to = NULL;
int load_from_clipboard = 0;
Selector=settings;
@ -1730,7 +1731,14 @@ byte Button_Load_or_Save(T_Selector_settings *settings, byte load, T_IO_Context
Window_display_icon_sprite(bookmark_dropdown[temp]->Pos_X+3,bookmark_dropdown[temp]->Pos_Y+2,ICON_STAR);
Display_bookmark(bookmark_dropdown[temp],temp);
}
#if defined(WIN32)
if (load)
Window_set_normal_button(62,180,115,14,"From Clipboard",0,1,MOD_CTRL|KEY_v); // 14
else
Window_set_normal_button(62,180,115,14,"To Clipboard",0,1,MOD_CTRL|KEY_c); // 14
#endif
Change_directory(context->File_directory);
Get_current_directory(Selector->Directory, Selector->Directory_unicode, MAX_PATH_CHARACTERS);
@ -2089,6 +2097,19 @@ byte Button_Load_or_Save(T_Selector_settings *settings, byte load, T_IO_Context
New_preview_is_needed=1;
Reset_quicksearch();
break;
case 14: // From/to clipboard
if (load)
{
// paste from clipboard
load_from_clipboard = 1;
New_preview_is_needed = 1;
Reset_quicksearch();
}
else
{
// copy to clipboard
}
break;
default:
if (clicked_button>=10 && clicked_button<10+NB_BOOKMARKS)
{
@ -2374,13 +2395,21 @@ byte Button_Load_or_Save(T_Selector_settings *settings, byte load, T_IO_Context
if (Timer_state==1) // Il faut afficher la preview
{
if ( (Selector->Position+Selector->Offset>=Filelist.Nb_directories) && (Filelist.Nb_elements) )
if ( load_from_clipboard || ((Selector->Position+Selector->Offset>=Filelist.Nb_directories) && (Filelist.Nb_elements)) )
{
T_IO_Context preview_context;
Init_context_preview(&preview_context, Selector_filename, Selector->Directory);
preview_context.Format = Selector->Format_filter;
preview_context.File_name_unicode = Selector_filename_unicode;
if (load_from_clipboard)
{
Init_context_preview(&preview_context, NULL, NULL);
preview_context.Format = FORMAT_CLIPBOARD;
}
else
{
Init_context_preview(&preview_context, Selector_filename, Selector->Directory);
preview_context.Format = Selector->Format_filter;
preview_context.File_name_unicode = Selector_filename_unicode;
}
Hide_cursor();
if (context->Type == CONTEXT_PALETTE)
preview_context.Type = CONTEXT_PREVIEW_PALETTE;
@ -2390,7 +2419,6 @@ byte Button_Load_or_Save(T_Selector_settings *settings, byte load, T_IO_Context
Update_window_area(0,0,Window_width,Window_height);
Display_cursor();
}
Timer_state=2; // On arrête le chrono
@ -2400,12 +2428,21 @@ byte Button_Load_or_Save(T_Selector_settings *settings, byte load, T_IO_Context
if (has_clicked_ok)
{
strcpy(context->File_name, Selector_filename);
if (context->File_name_unicode)
Unicode_strlcpy(context->File_name_unicode, Selector_filename_unicode, MAX_PATH_CHARACTERS);
strcpy(context->File_directory, Selector->Directory);
if (!load)
context->Format = Selector->Format_filter;
if (load_from_clipboard)
{
strcpy(context->File_name, "CLIPBOARD.GIF");
context->File_name_unicode[0] = 0;
context->Format = FORMAT_CLIPBOARD;
}
else
{
strcpy(context->File_name, Selector_filename);
if (context->File_name_unicode)
Unicode_strlcpy(context->File_name_unicode, Selector_filename_unicode, MAX_PATH_CHARACTERS);
strcpy(context->File_directory, Selector->Directory);
if (!load)
context->Format = Selector->Format_filter;
}
}
else
{

View File

@ -85,6 +85,9 @@ void Load_SDL_Image(T_IO_Context *);
void Load_Recoil_Image(T_IO_Context *);
#endif
// clipboard
static void Load_ClipBoard_Image(T_IO_Context *);
// ENUM Name TestFunc LoadFunc SaveFunc PalOnly Comment Layers Ext Exts
const T_Format File_formats[] = {
{FORMAT_ALL_IMAGES, "(all)", NULL, NULL, NULL, 0, 0, 0, "",
@ -578,82 +581,101 @@ void Load_image(T_IO_Context *context)
// charger le format du fichier:
File_error=1;
f = Open_file_read(context);
if (f == NULL)
if (context->Format == FORMAT_CLIPBOARD)
{
Warning("Cannot open file for reading");
Error(0);
return;
}
if (context->Format>FORMAT_ALL_FILES)
{
format = Get_fileformat(context->Format);
if (format->Test)
format->Test(context, f);
}
if (File_error)
{
// Sinon, on va devoir scanner les différents formats qu'on connait pour
// savoir à quel format est le fichier:
for (index=0; index < Nb_known_formats(); index++)
Load_ClipBoard_Image(context);
if (File_error != 0)
{
format = Get_fileformat(index);
// Loadable format
if (format->Test == NULL)
continue;
fseek(f, 0, SEEK_SET); // rewind
// On appelle le testeur du format:
format->Test(context, f);
// On s'arrête si le fichier est au bon format:
if (File_error==0)
break;
}
}
fclose(f);
if (File_error)
{
context->Format = DEFAULT_FILEFORMAT;
// try with recoil
#ifndef NORECOIL
Load_Recoil_Image(context);
if (File_error)
#endif
#if defined(USE_SDL) || defined(USE_SDL2)
{
// Last try: with SDL_image
Load_SDL_Image(context);
}
if (File_error)
#endif
{
// Sinon, l'appelant sera au courant de l'échec grace à File_error;
// et si on s'apprêtait à faire un chargement définitif de l'image (pas
// une preview), alors on flash l'utilisateur.
//if (Pixel_load_function!=Pixel_load_in_preview)
// Error(0);
Error(0);
return;
}
}
else
// Si on a su déterminer avec succès le format du fichier:
{
context->Format = format->Identifier;
// On peut charger le fichier:
// Dans certains cas il est possible que le chargement plante
// après avoir modifié la palette. TODO
format->Load(context);
}
if (File_error>0)
{
GFX2_Log(GFX2_WARNING, "Unable to load file %s (error %d)! format:%s\n", context->File_name, File_error, format->Label);
if (context->Type!=CONTEXT_SURFACE)
if (context->File_name == NULL || context->File_directory == NULL)
{
GFX2_Log(GFX2_ERROR, "Load_Image() called with NULL file name or directory\n");
Error(0);
return;
}
f = Open_file_read(context);
if (f == NULL)
{
Warning("Cannot open file for reading");
Error(0);
return;
}
if (context->Format > FORMAT_ALL_FILES)
{
format = Get_fileformat(context->Format);
if (format->Test)
format->Test(context, f);
}
if (File_error)
{
// Sinon, on va devoir scanner les différents formats qu'on connait pour
// savoir à quel format est le fichier:
for (index=0; index < Nb_known_formats(); index++)
{
format = Get_fileformat(index);
// Loadable format
if (format->Test == NULL)
continue;
fseek(f, 0, SEEK_SET); // rewind
// On appelle le testeur du format:
format->Test(context, f);
// On s'arrête si le fichier est au bon format:
if (File_error==0)
break;
}
}
fclose(f);
if (File_error)
{
context->Format = DEFAULT_FILEFORMAT;
// try with recoil
#ifndef NORECOIL
Load_Recoil_Image(context);
if (File_error)
#endif
#if defined(USE_SDL) || defined(USE_SDL2)
{
// Last try: with SDL_image
Load_SDL_Image(context);
}
if (File_error)
#endif
{
// Sinon, l'appelant sera au courant de l'échec grace à File_error;
// et si on s'apprêtait à faire un chargement définitif de l'image (pas
// une preview), alors on flash l'utilisateur.
//if (Pixel_load_function!=Pixel_load_in_preview)
// Error(0);
return;
}
}
else
// Si on a su déterminer avec succès le format du fichier:
{
context->Format = format->Identifier;
// On peut charger le fichier:
// Dans certains cas il est possible que le chargement plante
// après avoir modifié la palette. TODO
format->Load(context);
}
if (File_error>0)
{
GFX2_Log(GFX2_WARNING, "Unable to load file %s (error %d)! format:%s\n", context->File_name, File_error, format->Label);
if (context->Type!=CONTEXT_SURFACE)
Error(0);
}
}
// Post-load
@ -1186,6 +1208,162 @@ T_GFX2_Surface * Load_surface(char *full_name, T_Gradient_array *gradients)
}
static void Load_ClipBoard_Image(T_IO_Context * context)
{
#ifdef WIN32
UINT format;
HANDLE clipboard;
if (!OpenClipboard(GFX2_Get_Window_Handle()))
{
GFX2_Log(GFX2_ERROR, "Failed to open Clipboard\n");
return;
}
format = EnumClipboardFormats(0);
while (format != 0)
{
const char * format_name = NULL;
char format_name_buffer[256];
switch (format)
{
case CF_TEXT:
format_name = "TEXT";
break;
case CF_OEMTEXT:
format_name = "OEMTEXT";
break;
case CF_UNICODETEXT:
format_name = "UNICODE TEXT";
break;
case CF_DIB:
format_name = "DIB (BITMAPINFO)";
break;
case CF_DIBV5:
format_name = "DIBV5 (BITMAPV5HEADER)";
break;
case CF_BITMAP:
format_name = "HBITMAP";
break;
case CF_METAFILEPICT:
format_name = "METAFILEPICT";
break;
case CF_PALETTE:
format_name = "Palette";
break;
case CF_TIFF:
format_name = "TIFF";
break;
case CF_ENHMETAFILE:
format_name = "HENMETAFILE";
break;
default:
if (GetClipboardFormatNameA(format, format_name_buffer, sizeof(format_name_buffer)) <= 0)
GFX2_Log(GFX2_WARNING, "Failed to get name for clipboard format %u\n", format);
else
format_name = format_name_buffer;
}
if (format_name != NULL)
GFX2_Log(GFX2_DEBUG, "Available format %5u \"%s\"\n", format, format_name);
format = EnumClipboardFormats(format); // get next format
}
clipboard = GetClipboardData(CF_DIB);
if (clipboard != NULL)
{
const PBITMAPINFO bmi = (PBITMAPINFO)GlobalLock(clipboard);
if (bmi != NULL)
{
unsigned long width, height;
width = bmi->bmiHeader.biWidth;
height = (bmi->bmiHeader.biHeight > 0) ? bmi->bmiHeader.biHeight : -bmi->bmiHeader.biHeight;
GFX2_Log(GFX2_DEBUG, "DIB %ldx%ld planes=%u bpp=%u compression=%u size=%u ClrUsed=%u\n",
bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight,
bmi->bmiHeader.biPlanes, bmi->bmiHeader.biBitCount,
bmi->bmiHeader.biCompression, bmi->bmiHeader.biSizeImage,
bmi->bmiHeader.biClrUsed);
if (bmi->bmiHeader.biCompression != BI_RGB)
GFX2_Log(GFX2_INFO, "Unsupported DIB compression %u\n", bmi->bmiHeader.biCompression);
else if (width > 9999 || height > 9999)
GFX2_Log(GFX2_INFO, "Image too big : %lux%lu\n", width, height);
else
{
unsigned i, color_count;
const byte * pixels;
unsigned int x, y;
File_error = 0; // have to be set before calling Pre_load()
Pre_load(context, width, height, bmi->bmiHeader.biSizeImage, FORMAT_CLIPBOARD, PIXEL_SIMPLE, bmi->bmiHeader.biBitCount);
color_count = bmi->bmiHeader.biClrUsed;
if (bmi->bmiHeader.biBitCount <= 8)
{ // get palette
if (color_count == 0)
color_count = 1 << bmi->bmiHeader.biBitCount;
for (i = 0; i < color_count; i++)
{
context->Palette[i].R = bmi->bmiColors[i].rgbRed;
context->Palette[i].G = bmi->bmiColors[i].rgbGreen;
context->Palette[i].B = bmi->bmiColors[i].rgbBlue;
}
}
pixels = (const byte *)(&bmi->bmiColors[color_count]);
switch (bmi->bmiHeader.biBitCount)
{
case 8:
for (y = 0; y < height; y++)
{
const byte * line;
if (bmi->bmiHeader.biHeight > 0)
line = pixels + (height - y - 1) * bmi->bmiHeader.biWidth;
else
line = pixels + y * bmi->bmiHeader.biWidth;
for (x = 0; x < width; x++)
Set_pixel(context, x, y, line[x]);
}
break;
case 24:
for (y = 0; y < height; y++)
{
const byte * line;
if (bmi->bmiHeader.biHeight > 0)
line = pixels + (height - y - 1) * bmi->bmiHeader.biWidth * 3;
else
line = pixels + y * bmi->bmiHeader.biWidth * 3;
for (x = 0; x < width; x++)
Set_pixel_24b(context, x, y, line[x*3 + 2], line[x*3 + 1], line[x*3]);
}
break;
case 32:
for (y = 0; y < height; y++)
{
const byte * line;
if (bmi->bmiHeader.biHeight > 0)
line = pixels + (height - y - 1) * bmi->bmiHeader.biWidth * 4;
else
line = pixels + y * bmi->bmiHeader.biWidth * 4;
for (x = 0; x < width; x++)
Set_pixel_24b(context, x, y, line[x*4 + 2], line[x*4 + 1], line[x*4]);
}
break;
default:
GFX2_Log(GFX2_ERROR, "Loading %ubpp pictures from Clipboard is not implemented yet!\n", bmi->bmiHeader.biBitCount);
File_error = 1;
}
}
GlobalUnlock(clipboard);
}
}
CloseClipboard();
#else
GFX2_Log(GFX2_ERROR, "Load_ClipBoard_Image() not implemented on this platform yet\n");
File_error = 1;
#endif
}
/// Saves an image.
/// This routine will only be called when all hope is lost, memory thrashed, etc
/// It's the last chance to save anything, but the code has to be extremely