diff --git a/NEWS.txt b/NEWS.txt index 74503f5c8..151213663 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -2,9 +2,10 @@ NEWS =================================== -0.7 ---- +0.6.2 +----- ++ Copy & Paste use Windows clipboard (feature #2577954). + Added "Save Copy As" command (feature #2636076). + Fixed compilation support for gcc 64 bits. + Fixed a bug with multiple editors and paste command. diff --git a/config.h b/config.h index 548ee7bf4..cc122c6de 100644 --- a/config.h +++ b/config.h @@ -24,7 +24,7 @@ /* general information */ #define PACKAGE "ASE" -#define VERSION "0.6.1" +#define VERSION "0.6.2" #define WEBSITE "http://www.aseprite.org/" #define COPYRIGHT "Copyright (C) 2001-2009 David Capello" diff --git a/makefile.lst b/makefile.lst index a358839f8..d1d247f06 100644 --- a/makefile.lst +++ b/makefile.lst @@ -188,7 +188,7 @@ COMMON_SOURCES = \ src/util/autocrop.cpp \ src/util/boundary.cpp \ src/util/celmove.cpp \ - src/util/clipbrd.cpp \ + src/util/clipboard.cpp \ src/util/col_file.cpp \ src/util/filetoks.cpp \ src/util/functions.cpp \ diff --git a/misc/dist.sh b/misc/dist.sh index 1bc1c73a9..e30cde70d 100644 --- a/misc/dist.sh +++ b/misc/dist.sh @@ -1,7 +1,7 @@ #! /bin/sh dir="`pwd`" -version=0.6.1 +version=0.6.2 distdir=ase-$version freetype_files="third_party/freetype/ChangeLog \ diff --git a/src/commands/cmd_copy.cpp b/src/commands/cmd_copy.cpp index 362aea60a..411d4847a 100644 --- a/src/commands/cmd_copy.cpp +++ b/src/commands/cmd_copy.cpp @@ -25,7 +25,7 @@ #include "raster/layer.h" #include "raster/mask.h" #include "raster/sprite.h" -#include "util/clipbrd.h" +#include "util/clipboard.h" #include "util/misc.h" static bool cmd_copy_enabled(const char *argument) @@ -43,7 +43,7 @@ static bool cmd_copy_enabled(const char *argument) static void cmd_copy_execute(const char *argument) { - copy_to_clipboard(); + clipboard::copy(current_sprite); } Command cmd_copy = { diff --git a/src/commands/cmd_cut.cpp b/src/commands/cmd_cut.cpp index 192de8f16..fc11a1273 100644 --- a/src/commands/cmd_cut.cpp +++ b/src/commands/cmd_cut.cpp @@ -25,7 +25,7 @@ #include "raster/layer.h" #include "raster/mask.h" #include "raster/sprite.h" -#include "util/clipbrd.h" +#include "util/clipboard.h" #include "util/misc.h" static bool cmd_cut_enabled(const char *argument) @@ -43,7 +43,7 @@ static bool cmd_cut_enabled(const char *argument) static void cmd_cut_execute(const char *argument) { - cut_to_clipboard(); + clipboard::cut(current_sprite); } Command cmd_cut = { diff --git a/src/commands/cmd_exit.cpp b/src/commands/cmd_exit.cpp index 9c1f14963..9f0936593 100644 --- a/src/commands/cmd_exit.cpp +++ b/src/commands/cmd_exit.cpp @@ -28,13 +28,10 @@ static void cmd_exit_execute(const char *argument) { Sprite *sprite = get_first_sprite(); - Sprite *clipboard = get_clipboard_sprite(); while (sprite) { - /* check if this sprite is modified */ - - if (sprite_is_modified(sprite) && - (!clipboard || sprite->id != clipboard->id)) { + // check if this sprite is modified + if (sprite_is_modified(sprite)) { if (jalert(_("Warning<undo)) undo_set_label(current_sprite->undo, "Paste"); - paste_from_clipboard(); + clipboard::paste(current_sprite); } Command cmd_paste = { diff --git a/src/dialogs/drawtext.cpp b/src/dialogs/drawtext.cpp index af3a5a69f..7d7d0310c 100644 --- a/src/dialogs/drawtext.cpp +++ b/src/dialogs/drawtext.cpp @@ -35,7 +35,7 @@ #include "raster/blend.h" #include "raster/image.h" #include "raster/sprite.h" -#include "util/clipbrd.h" +#include "util/clipboard.h" #include "util/misc.h" #include "widgets/colbar.h" #include "widgets/colbut.h" @@ -137,8 +137,9 @@ void dialogs_draw_text() /* render text */ image = render_text(f, text, color); if (image) { - copy_image_to_clipboard(image); - paste_from_clipboard(); + clipboard::copy_image(image, sprite_get_palette(current_sprite, + current_sprite->frame)); + clipboard::paste(current_sprite); } else console_printf(_("Error rendering text.\n")); diff --git a/src/modules/editors.cpp b/src/modules/editors.cpp index 8b37e6fcc..a8650d0c2 100644 --- a/src/modules/editors.cpp +++ b/src/modules/editors.cpp @@ -420,14 +420,13 @@ static int is_sprite_in_some_editor(Sprite *sprite) */ static Sprite *get_more_reliable_sprite() { - Sprite *clipboard = get_clipboard_sprite(); Sprite *sprite; JLink link; JI_LIST_FOR_EACH(get_sprite_list(), link) { sprite = reinterpret_cast(link->data); - if ((sprite != clipboard) && !(is_sprite_in_some_editor(sprite))) + if (!(is_sprite_in_some_editor(sprite))) return sprite; } diff --git a/src/modules/gui.cpp b/src/modules/gui.cpp index 58c65c4f8..5350e3c21 100644 --- a/src/modules/gui.cpp +++ b/src/modules/gui.cpp @@ -846,6 +846,7 @@ static bool manager_msg_proc(JWidget widget, JMessage msg) /* ok, so we can execute the command represented by the pressed-key in the message... */ if (command_is_enabled(command, NULL)) { + // if a menu is open, close everything command_execute(command, NULL); return TRUE; } diff --git a/src/modules/sprites.cpp b/src/modules/sprites.cpp index 6da1f8a2c..e3fb90bbf 100644 --- a/src/modules/sprites.cpp +++ b/src/modules/sprites.cpp @@ -46,7 +46,6 @@ Sprite* current_sprite = NULL; static JList sprites_list; -static Sprite* clipboard_sprite; static ImageRef *images_ref_get_from_layer(Sprite* sprite, Layer *layer, int target, bool write); static void layer_get_pos(Sprite* sprite, Layer *layer, int target, bool write, int **x, int **y, int *count); @@ -54,7 +53,6 @@ static void layer_get_pos(Sprite* sprite, Layer *layer, int target, bool write, int init_module_sprites() { sprites_list = jlist_new(); - clipboard_sprite = NULL; current_sprite = NULL; return 0; } @@ -63,11 +61,6 @@ void exit_module_sprites() { JLink link; - if (clipboard_sprite) { - sprite_free(clipboard_sprite); - clipboard_sprite = NULL; - } - JI_LIST_FOR_EACH(sprites_list, link) { sprite_free(reinterpret_cast(link->data)); } @@ -98,29 +91,6 @@ Sprite* get_next_sprite(Sprite* sprite) return NULL; } -Sprite* get_clipboard_sprite() -{ - return clipboard_sprite; -} - -void set_clipboard_sprite(Sprite* sprite) -{ - if (clipboard_sprite) { - if (current_sprite == clipboard_sprite) - set_current_sprite(sprite); - - if (is_interactive()) - replace_sprite_in_editors(clipboard_sprite, sprite); - - sprite_free(clipboard_sprite); - } - - clipboard_sprite = sprite; - - if (is_interactive()) - app_realloc_sprite_list(); -} - /* adds the "sprite" in the list of sprites */ void sprite_mount(Sprite* sprite) { @@ -143,10 +113,6 @@ void sprite_unmount(Sprite* sprite) /* remove from the sprite's list */ jlist_remove(sprites_list, sprite); - /* remove from the clipboard pointer */ - if (sprite == get_clipboard_sprite()) - clipboard_sprite = NULL; - if (is_interactive()) { /* remove this sprite from tabs */ tabs_remove_tab(app_get_tabsbar(), sprite); diff --git a/src/modules/sprites.h b/src/modules/sprites.h index dced3131a..7384655a9 100644 --- a/src/modules/sprites.h +++ b/src/modules/sprites.h @@ -43,9 +43,6 @@ JList get_sprite_list(); Sprite* get_first_sprite(); Sprite* get_next_sprite(Sprite* sprite); -Sprite* get_clipboard_sprite(); -void set_clipboard_sprite(Sprite* sprite); - void sprite_mount(Sprite* sprite); void sprite_unmount(Sprite* sprite); diff --git a/src/util/boundary.cpp b/src/util/boundary.cpp index e4e8c0000..4199ffb49 100644 --- a/src/util/boundary.cpp +++ b/src/util/boundary.cpp @@ -18,7 +18,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Adapted to ASE by David Capello (2003-2009) - * See "LICENSE.txt" for more information. + * See "LEGAL.txt" for more information. */ #include "config.h" diff --git a/src/util/clipbrd.cpp b/src/util/clipboard.cpp similarity index 81% rename from src/util/clipbrd.cpp rename to src/util/clipboard.cpp index 4a060520e..bdf893b8c 100644 --- a/src/util/clipbrd.cpp +++ b/src/util/clipboard.cpp @@ -18,6 +18,7 @@ #include "config.h" +#include #include #include @@ -35,16 +36,22 @@ #include "raster/cel.h" #include "raster/image.h" #include "raster/layer.h" +#include "raster/palette.h" #include "raster/rotate.h" #include "raster/sprite.h" #include "raster/stock.h" #include "raster/undoable.h" #include "raster/undo.h" -#include "util/clipbrd.h" +#include "util/clipboard.h" #include "util/misc.h" #include "widgets/colbar.h" #include "widgets/statebar.h" +#if defined ALLEGRO_WINDOWS +#include +#include "util/clipboard_win32.h" +#endif + #define SCALE_MODE 0 #define ROTATE_MODE 1 @@ -69,11 +76,13 @@ enum { ACTION_ROTATE_BR, }; -static bool interactive_transform(JWidget widget, - Image *dest_image, Image *image, - int x, int y, - int xout[4], int yout[4]); -static int low_copy(); +static void destroy_clipboard(void* data); +static void set_clipboard(Image* image, Palette* palette, bool set_system_clipboard); +static bool copy_from_sprite(Sprite* sprite); +static ase_uint32 get_shift_from_mask(ase_uint32 mask); + +static bool interactive_transform(JWidget widget, Image *dest_image, Image *image, + int x, int y, int xout[4], int yout[4]); static void apply_rotation(int x1, int y1, int x2, int y2, fixed angle, int cx, int cy, int xout[4], int yout[4]); @@ -87,59 +96,78 @@ static void fill_in_vars(int *in_box, int *in_top, int *in_middle, int *in_bottom, int x1, int y1, int x2, int y2, fixed angle, int cx, int cy); -static void update_status_bar(JWidget editor, Image *image, +static void update_status_bar(JWidget editor, Image *image, int x1, int y1, int x2, int y2, fixed angle); -bool has_clipboard_image(int *w, int *h) +static bool first_time = true; + +static Palette* clipboard_palette = NULL; +static Image* clipboard_image = NULL; + +static void destroy_clipboard(void* data) { - Sprite *clipboard = get_clipboard_sprite(); - Image *image = NULL; - Cel *cel; - - if (clipboard) { - cel = layer_get_cel(clipboard->layer, clipboard->frame); - if (cel) - image = stock_get_image(clipboard->stock, cel->image); - } - - if (image) { - if (w) *w = image->w; - if (h) *h = image->h; - return TRUE; - } - else { - if (w) *w = 0; - if (h) *h = 0; - return FALSE; - } + delete clipboard_palette; + delete clipboard_image; } -void copy_image_to_clipboard(Image *image) +static void set_clipboard(Image* image, Palette* palette, bool set_system_clipboard) { - Sprite *sprite; - Image *dest; - - sprite = sprite_new_with_layer(image->imgtype, image->w, image->h); - if (sprite) { - dest = GetImage2(sprite, NULL, NULL, NULL); - image_copy(dest, image, 0, 0); - - sprite_set_palette(sprite, get_current_palette(), FALSE); - - set_clipboard_sprite(sprite); + if (first_time) { + first_time = false; + app_add_hook(APP_EXIT, destroy_clipboard, NULL); } + + delete clipboard_palette; + delete clipboard_image; + + clipboard_palette = palette; + clipboard_image = image; + + // copy to the Windows clipboard +#ifdef ALLEGRO_WINDOWS + if (set_system_clipboard) + set_win32_clipboard_bitmap(image, palette); +#endif } -void cut_to_clipboard() +static bool copy_from_sprite(Sprite* sprite) { - if (current_sprite == NULL || - current_sprite->layer == NULL) - return; + assert(sprite); + Image* image = NewImageFromMask(sprite); + if (!image) + return false; - if (!low_copy()) + Palette* pal = sprite_get_palette(sprite, sprite->frame); + set_clipboard(image, pal ? palette_new_copy(pal): NULL, true); + return true; +} + +static ase_uint32 get_shift_from_mask(ase_uint32 mask) +{ + ase_uint32 shift = 0; + for (shift=0; shift<32; ++shift) + if (mask & (1 << shift)) + return shift; + return shift; +} + +bool clipboard::can_paste() +{ +#ifdef ALLEGRO_WINDOWS + if (win32_clipboard_contains_bitmap()) + return true; +#endif + return clipboard_image != NULL; +} + +void clipboard::cut(Sprite* sprite) +{ + assert(sprite != NULL); + assert(sprite->layer != NULL); + + if (!copy_from_sprite(sprite)) console_printf("Can't copying an image portion from the current layer\n"); else { - Sprite* sprite = current_sprite; { Undoable undoable(sprite, "Cut"); undoable.clear_mask(app_get_color_to_clear_layer(sprite->layer)); @@ -149,55 +177,63 @@ void cut_to_clipboard() } } -void copy_to_clipboard() +void clipboard::copy(Sprite* sprite) { - if (!current_sprite) - return; + assert(sprite != NULL); - if (!low_copy()) + if (!copy_from_sprite(sprite)) console_printf(_("Can't copying an image portion from the current layer\n")); } -void paste_from_clipboard() +void clipboard::copy_image(Image* image, Palette* pal) +{ + set_clipboard(image_new_copy(image), + pal ? palette_new_copy(pal): NULL, true); +} + +void clipboard::paste(Sprite* sprite) { - Sprite *clipboard = get_clipboard_sprite(); - Cel *cel; - Image *image; - Image *dest_image; int xout[4], yout[4]; - int dest_x, dest_y; + int dst_x, dst_y; + Image *src_image; + Image* dst_image; bool paste; - if (!current_sprite || - current_sprite == clipboard || - !clipboard->layer || - !is_interactive()) - return; - - if (clipboard->imgtype != current_sprite->imgtype) { - /* TODO now the user can't select the clipboard sprite */ - console_printf(_("You can't copy sprites of different image types.\nYou should select the clipboard sprite, and change the image type of it.\n")); - return; +#ifdef ALLEGRO_WINDOWS + { + Image* win32_image = NULL; + Palette* win32_palette = NULL; + get_win32_clipboard_bitmap(win32_image, win32_palette); + if (win32_image != NULL) + set_clipboard(win32_image, win32_palette, false); } - - cel = layer_get_cel(clipboard->layer, clipboard->frame); - if (!cel) { - console_printf(_("Error: No cel in the clipboard\n")); +#endif + if (clipboard_image == NULL) return; - } - image = stock_get_image(clipboard->stock, cel->image); - if (!image) { - console_printf(_("Error: No image in the clipboard\n")); - return; - } + assert(sprite != NULL); - dest_image = GetImage2(current_sprite, &dest_x, &dest_y, NULL); - if (!dest_image) { + // destination image (where to put this image) + dst_image = GetImage2(sprite, &dst_x, &dst_y, NULL); + if (!dst_image) { console_printf(_("Error: no destination image\n")); return; } + // source image (clipboard or a converted copy to the destination 'imgtype') + if (clipboard_image->imgtype == sprite->imgtype) + src_image = clipboard_image; + else { + src_image = image_new(sprite->imgtype, + clipboard_image->w, + clipboard_image->h); + + use_current_sprite_rgb_map(); + image_convert(src_image, clipboard_image); + restore_rgb_map(); + } + + // do the interactive-transform loop (where the user can move the floating image) { JWidget view = jwidget_get_view(current_editor); JRect vp = jview_get_viewport_position(view); @@ -205,11 +241,11 @@ void paste_from_clipboard() screen_to_editor(current_editor, vp->x1, vp->y1, &x1, &y1); screen_to_editor(current_editor, vp->x2-1, vp->y2-1, &x2, &y2); - x = (x1+x2)/2-image->w/2; - y = (y1+y2)/2-image->h/2; + x = (x1+x2)/2-src_image->w/2; + y = (y1+y2)/2-src_image->h/2; paste = interactive_transform(current_editor, - dest_image, image, x, y, xout, yout); + dst_image, src_image, x, y, xout, yout); jrect_free(vp); } @@ -219,39 +255,41 @@ void paste_from_clipboard() /* align to the destination cel-position */ for (c=0; c<4; ++c) { - xout[c] -= dest_x; - yout[c] -= dest_y; + xout[c] -= dst_x; + yout[c] -= dst_y; } /* clip the box for the undo */ u1 = MAX(0, MIN(xout[0], MIN(xout[1], MIN(xout[2], xout[3])))); v1 = MAX(0, MIN(yout[0], MIN(yout[1], MIN(yout[2], yout[3])))); - u2 = MIN(dest_image->w-1, MAX(xout[0], MAX(xout[1], MAX(xout[2], xout[3])))); - v2 = MIN(dest_image->h-1, MAX(yout[0], MAX(yout[1], MAX(yout[2], yout[3])))); + u2 = MIN(dst_image->w-1, MAX(xout[0], MAX(xout[1], MAX(xout[2], xout[3])))); + v2 = MIN(dst_image->h-1, MAX(yout[0], MAX(yout[1], MAX(yout[2], yout[3])))); w = u2-u1+1; h = v2-v1+1; if (w >= 1 && h >= 1) { /* undo region */ - if (undo_is_enabled(current_sprite->undo)) - undo_image(current_sprite->undo, dest_image, u1, v1, w, h); + if (undo_is_enabled(sprite->undo)) + undo_image(sprite->undo, dst_image, u1, v1, w, h); /* draw the transformed image */ - image_parallelogram(dest_image, image, + image_parallelogram(dst_image, src_image, xout[0], yout[0], xout[1], yout[1], xout[2], yout[2], xout[3], yout[3]); } } - update_screen_for_sprite(current_sprite); + if (src_image != clipboard_image) + image_free(src_image); + update_screen_for_sprite(sprite); } /**********************************************************************/ /* interactive transform */ enum { DONE_NONE, DONE_CANCEL, DONE_PASTE }; - + static bool interactive_transform(JWidget widget, Image *dest_image, Image *image, int x, int y, @@ -282,10 +320,11 @@ static bool interactive_transform(JWidget widget, int action = ACTION_SETMODE; int mode = SCALE_MODE; BITMAP *bmp1, *bmp2, *preview, *old_screen; - JRect vp = jview_get_viewport_position (jwidget_get_view (widget)); + JRect vp = jview_get_viewport_position(jwidget_get_view(widget)); int done = DONE_NONE; fixed angle = 0; int cx, cy; + int mask_color; hide_drawing_cursor(widget); @@ -305,6 +344,7 @@ static bool interactive_transform(JWidget widget, /* generate the preview bitmap (for fast-blitting) */ preview = create_bitmap(image->w, image->h); + mask_color = bitmap_mask_color(preview); image_to_allegro(image, preview, 0, 0); switch (image->imgtype) { @@ -313,8 +353,8 @@ static bool interactive_transform(JWidget widget, int x, y; for (y=0; yh; y++) for (x=0; xw; x++) - if (_rgba_geta(image_getpixel(image, x, y)) < 128) - putpixel(preview, x, y, bitmap_mask_color(preview)); + if (_rgba_geta(image->method->getpixel(image, x, y)) < 128) + putpixel(preview, x, y, mask_color); break; } @@ -322,8 +362,17 @@ static bool interactive_transform(JWidget widget, int x, y; for (y=0; yh; y++) for (x=0; xw; x++) - if (_graya_geta(image_getpixel(image, x, y)) < 128) - putpixel(preview, x, y, bitmap_mask_color(preview)); + if (_graya_geta(image->method->getpixel(image, x, y)) < 128) + putpixel(preview, x, y, mask_color); + break; + } + + case IMAGE_INDEXED: { + int x, y; + for (y=0; yh; y++) + for (x=0; xw; x++) + if (image->method->getpixel(image, x, y) == 0) + putpixel(preview, x, y, mask_color); break; } } @@ -588,7 +637,7 @@ static bool interactive_transform(JWidget widget, x2 += x1 - ox; y2 += y1 - oy; } - + editor_to_screen(widget, x1, y1, &x1, &y1); editor_to_screen(widget, x2, y2, &x2, &y2); @@ -648,40 +697,6 @@ static bool interactive_transform(JWidget widget, return done == DONE_PASTE; } -static int low_copy() -{ - Sprite *sprite; - Layer *layer; - - sprite = sprite_new(current_sprite->imgtype, - current_sprite->w, - current_sprite->h); - if (!sprite) - return FALSE; - - /* set the current frame */ - sprite_set_frame(sprite, current_sprite->frame); - - /* create a new layer from the current mask (in the current - frame) */ - layer = NewLayerFromMask(current_sprite, sprite); - if (!layer) { - sprite_free(sprite); - return FALSE; - } - - layer_add_layer(sprite->set, layer); - sprite_set_layer(sprite, layer); - - sprite_set_palette(sprite, - sprite_get_palette(current_sprite, - current_sprite->frame), 0); - - set_clipboard_sprite(sprite); - - return TRUE; -} - static void apply_rotation(int x1, int y1, int x2, int y2, fixed angle, int cx, int cy, int xout[4], int yout[4]) diff --git a/src/util/clipbrd.h b/src/util/clipboard.h similarity index 82% rename from src/util/clipbrd.h rename to src/util/clipboard.h index d89720d7c..022e28027 100644 --- a/src/util/clipbrd.h +++ b/src/util/clipboard.h @@ -23,13 +23,16 @@ class Image; -bool has_clipboard_image(int *w, int *h); +namespace clipboard { -void copy_image_to_clipboard(Image* image); +bool can_paste(); -void cut_to_clipboard(); -void copy_to_clipboard(); -void paste_from_clipboard(); +void cut(Sprite* sprite); +void copy(Sprite* sprite); +void copy_image(Image* image, Palette* palette); +void paste(Sprite* sprite); + +} // namespace clipboard #endif /* UTIL_CLIPBRD_H */ diff --git a/src/util/clipboard_win32.h b/src/util/clipboard_win32.h new file mode 100644 index 000000000..6c08903f8 --- /dev/null +++ b/src/util/clipboard_win32.h @@ -0,0 +1,268 @@ +/* ASE - Allegro Sprite Editor + * Copyright (C) 2001-2009 David Capello + * + * This program 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// included by clipboard.cpp + +/** + * Returns true if the Windows clipboard contains a bitmap (CF_DIB + * format). + */ +static bool win32_clipboard_contains_bitmap() +{ + return IsClipboardFormatAvailable(CF_DIB); +} + +/** + * Changes the Windows clipboard content to the specified image. The + * palette is optional and only used if the image is IMAGE_INDEXED type. + */ +static void set_win32_clipboard_bitmap(Image* image, Palette* palette) +{ + if (!OpenClipboard(win_get_window())) + return; + + if (!EmptyClipboard()) { + CloseClipboard(); + return; + } + + // information to create the memory necessary for the bitmap + int padding = 0; + int scanline = 0; + int color_depth = 0; + int palette_entries = 0; + + switch (image->imgtype) { + case IMAGE_RGB: + scanline = sizeof(ase_uint32) * image->w; + color_depth = 32; + break; + case IMAGE_GRAYSCALE: + // this is right! Grayscaled is copied as RGBA in Win32 Clipboard + scanline = sizeof(ase_uint32) * image->w; + color_depth = 32; + break; + case IMAGE_INDEXED: + padding = (4-(image->w&3))&3; + scanline = sizeof(ase_uint8) * image->w; + scanline += padding; + color_depth = 8; + palette_entries = palette->ncolors; + break; + } + assert(scanline > 0 && color_depth > 0); + + // create the BITMAPV5HEADER structure + HGLOBAL hmem = GlobalAlloc(GHND, + sizeof(BITMAPV5HEADER) + + palette_entries*sizeof(RGBQUAD) + + scanline*image->h); + BITMAPV5HEADER* bi = (BITMAPV5HEADER*)GlobalLock(hmem); + + bi->bV5Size = sizeof(BITMAPV5HEADER); + bi->bV5Width = image->w; + bi->bV5Height = image->h; + bi->bV5Planes = 1; + bi->bV5BitCount = color_depth; + bi->bV5Compression = BI_RGB; + bi->bV5SizeImage = scanline*image->h; + bi->bV5RedMask = 0x00ff0000; + bi->bV5GreenMask = 0x0000ff00; + bi->bV5BlueMask = 0x000000ff; + bi->bV5AlphaMask = 0xff000000; + bi->bV5CSType = LCS_WINDOWS_COLOR_SPACE; + bi->bV5Intent = LCS_GM_GRAPHICS; + bi->bV5ClrUsed = palette_entries == 256 ? 0: palette_entries; + + // write pixels + switch (image->imgtype) { + case IMAGE_RGB: { + ase_uint32* dst = (ase_uint32*)(((ase_uint8*)bi)+bi->bV5Size); + ase_uint32 c; + for (int y=image->h-1; y>=0; --y) + for (int x=0; xw; ++x) { + c = image->method->getpixel(image, x, y); + *(dst++) = ((_rgba_getb(c) << 0) | + (_rgba_getg(c) << 8) | + (_rgba_getr(c) << 16) | + (_rgba_geta(c) << 24)); + } + break; + } + case IMAGE_GRAYSCALE: { + ase_uint32* dst = (ase_uint32*)(((ase_uint8*)bi)+bi->bV5Size); + ase_uint16 c; + for (int y=image->h-1; y>=0; --y) + for (int x=0; xw; ++x) { + c = image->method->getpixel(image, x, y); + *(dst++) = ((_graya_getv(c) << 0) | + (_graya_getv(c) << 8) | + (_graya_getv(c) << 16) | + (_graya_geta(c) << 24)); + } + break; + } + case IMAGE_INDEXED: { + Palette* palette = get_current_palette(); + RGBQUAD* rgbquad = (RGBQUAD*)(((ase_uint8*)bi)+bi->bV5Size); + for (int i=0; incolors; ++i) { + rgbquad->rgbRed = _rgba_getr(palette->color[i]); + rgbquad->rgbGreen = _rgba_getg(palette->color[i]); + rgbquad->rgbBlue = _rgba_getb(palette->color[i]); + rgbquad++; + } + + ase_uint8* dst = (ase_uint8*)(((ase_uint8*)bi)+bi->bV5Size + + palette_entries*sizeof(RGBQUAD)); + for (int y=image->h-1; y>=0; --y) { + for (int x=0; xw; ++x) { + *(dst++) = image->method->getpixel(image, x, y); + } + dst += padding; + } + break; + } + } + + GlobalUnlock(hmem); + SetClipboardData(CF_DIBV5, hmem); + CloseClipboard(); + + GlobalFree(hmem); +} + +/** + * Creates an Image from the current Windows Clipboard content. + */ +static void get_win32_clipboard_bitmap(Image*& image, Palette*& palette) +{ + image = NULL; + palette = NULL; + + if (!win32_clipboard_contains_bitmap()) + return; + + if (!OpenClipboard(win_get_window())) + return; + + BITMAPINFO* bi = (BITMAPINFO*)GetClipboardData(CF_DIB); + if (bi && bi->bmiHeader.biCompression == BI_RGB) { + try { + image = image_new(bi->bmiHeader.biBitCount == 8 ? IMAGE_INDEXED: + IMAGE_RGB, + bi->bmiHeader.biWidth, + ABS(bi->bmiHeader.biHeight)); + + bool valid_image = false; + switch (bi->bmiHeader.biBitCount) { + case 32: { + // BITMAPV5HEADER* bv5 = (BITMAPV5HEADER*)GetClipboardData(CF_DIBV5); + // ase_uint32* src = (ase_uint32*)(((ase_uint8*)bv5)+bv5->bV5Size); + ase_uint32* src = (ase_uint32*)(((ase_uint8*)bi)+bi->bmiHeader.biSize); + ase_uint32 c; + // int r_shift = get_shift_from_mask(bv5->bV5RedMask); + // int g_shift = get_shift_from_mask(bv5->bV5GreenMask); + // int b_shift = get_shift_from_mask(bv5->bV5BlueMask); + // int a_shift = get_shift_from_mask(bv5->bV5AlphaMask); + + for (int y=image->h-1; y>=0; --y) { + for (int x=0; xw; ++x) { + c = *(src++); + // image->method->putpixel(image, x, y, + // _rgba((c & bv5->bV5RedMask) >> r_shift, + // (c & bv5->bV5GreenMask) >> g_shift, + // (c & bv5->bV5BlueMask) >> b_shift, + // (c & bv5->bV5AlphaMask) >> a_shift)); + image->method->putpixel(image, x, y, + _rgba((c & 0x00ff0000) >> 16, + (c & 0x0000ff00) >> 8, + (c & 0x000000ff) >> 0, + (c & 0xff000000) >> 24)); + } + } + valid_image = true; + break; + } + case 24: { + ase_uint8* src = (((ase_uint8*)bi)+bi->bmiHeader.biSize); + ase_uint8 r, g, b; + int padding = (4-(image->w*3)&3)&3; + + for (int y=image->h-1; y>=0; --y) { + for (int x=0; xw; ++x) { + b = *(src++); + g = *(src++); + r = *(src++); + image->method->putpixel(image, x, y, _rgba(r, g, b, 255)); + } + src += padding; + } + valid_image = true; + break; + } + case 16: { + // TODO + break; + } + case 8: { + int colors = bi->bmiHeader.biClrUsed > 0 ? bi->bmiHeader.biClrUsed: 256; + palette = palette_new(0, 256); + for (int c=0; c<256; ++c) { + int alpha = (c == 0) ? 0: 255; + if (c < colors) { + palette->color[c] = _rgba(bi->bmiColors[c].rgbRed, + bi->bmiColors[c].rgbGreen, + bi->bmiColors[c].rgbBlue, alpha); + } + else { + palette->color[c] = _rgba(0, 0, 0, alpha); + } + } + + ase_uint8* src = (((ase_uint8*)bi)+bi->bmiHeader.biSize+sizeof(RGBQUAD)*colors); + int padding = (4-(image->w&3))&3; + + for (int y=image->h-1; y>=0; --y) { + for (int x=0; xw; ++x) + image->method->putpixel(image, x, y, *(src++) & 0xff); + + src += padding; + } + + valid_image = true; + break; + } + } + + if (!valid_image) { + delete image; + delete palette; + image = NULL; + palette = NULL; + } + } + catch (...) { + delete image; + delete palette; + image = NULL; + palette = NULL; + } + } + + CloseClipboard(); +} diff --git a/src/util/misc.cpp b/src/util/misc.cpp index 0af9caaf4..74e81bdc4 100644 --- a/src/util/misc.cpp +++ b/src/util/misc.cpp @@ -174,6 +174,50 @@ Layer *NewLayerFromMask(Sprite *src_sprite, Sprite *dst_sprite) return layer; } +Image* NewImageFromMask(Sprite* src_sprite) +{ + ase_uint8 *address; + int x, y, u, v, getx, gety; + Image *dst, *src = GetImage2(src_sprite, &x, &y, NULL); + div_t d; + + assert(src_sprite); + assert(src_sprite->mask); + assert(src_sprite->mask->bitmap); + assert(src); + + dst = image_new(src_sprite->imgtype, + src_sprite->mask->w, + src_sprite->mask->h); + if (!dst) + return NULL; + + /* clear the new image */ + image_clear(dst, 0); + + /* copy the masked zones */ + for (v=0; vmask->h; v++) { + d = div(0, 8); + address = ((ase_uint8 **)src_sprite->mask->bitmap->line)[v]+d.quot; + + for (u=0; umask->w; u++) { + if ((*address & (1<mask->x-x; + gety = v+src_sprite->mask->y-y; + + if ((getx >= 0) && (getx < src->w) && + (gety >= 0) && (gety < src->h)) + dst->method->putpixel(dst, u, v, + src->method->getpixel(src, getx, gety)); + } + + _image_bitmap_next_bit(d, address); + } + } + + return dst; +} + Image *GetLayerImage(Layer *layer, int *x, int *y, int frame) { Image *image = NULL; diff --git a/src/util/misc.h b/src/util/misc.h index fe69c0948..69b080e2e 100644 --- a/src/util/misc.h +++ b/src/util/misc.h @@ -34,6 +34,7 @@ Image* GetImage2(Sprite* sprite, int *x, int *y, int *opacity); void LoadPalette(const char* filename); Layer* NewLayerFromMask(Sprite* src, Sprite* dst); +Image* NewImageFromMask(Sprite* src); Image* GetLayerImage(Layer* layer, int *x, int *y, int frame);