From 4f73c24989fde98523935c453aa39c1bcf6868cc Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Tue, 9 Feb 2010 20:04:56 +0000 Subject: [PATCH] Added Layer menu. Issue 263 and issue 110: Added background transparency, for GIF and PNG formats (tested OK in Load, Save, and preview git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@1332 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- fileformats.c | 56 +++++++++-- .../{GrafX2_Classic.gif => GrafX2_Black.gif} | Bin 1719 -> 1727 bytes fonts/GrafX2_Dark.gif | Bin 0 -> 1727 bytes layers.c | 88 ++++++++++++++++++ loadsave.c | 21 ++++- loadsave.h | 8 +- pages.c | 1 + struct.h | 3 +- 8 files changed, 163 insertions(+), 14 deletions(-) rename fonts/{GrafX2_Classic.gif => GrafX2_Black.gif} (82%) create mode 100644 fonts/GrafX2_Dark.gif diff --git a/fileformats.c b/fileformats.c index 2244b8e5..1ae2eec2 100644 --- a/fileformats.c +++ b/fileformats.c @@ -1672,8 +1672,7 @@ word GIF_get_next_code(void) void GIF_new_pixel(T_IO_Context * context, T_GIF_IDB *idb, byte color) { - if (color != context->Transparent_color) // transparent color - Set_pixel(context, idb->Pos_X+GIF_pos_X, idb->Pos_Y+GIF_pos_Y,color); + Set_pixel(context, idb->Pos_X+GIF_pos_X, idb->Pos_Y+GIF_pos_Y,color); GIF_pos_X++; @@ -1855,9 +1854,17 @@ void Load_GIF(T_IO_Context * context) && Read_byte(GIF_file,&(GCE.Transparent_color))) { if (GCE.Packed_fields & 1) + { + if (number_LID == 0) + context->Background_transparent = 1; context->Transparent_color= GCE.Transparent_color; + } else - context->Transparent_color = -1; + { + if (number_LID == 0) + context->Background_transparent = 0; + context->Transparent_color = 0; // Reset transparent color + } } else @@ -2170,7 +2177,7 @@ void Save_GIF(T_IO_Context * context) LSDB.Height=context->Height; } LSDB.Resol =0x97; // Image en 256 couleurs, avec une palette - LSDB.Backcol=0; + LSDB.Backcol=context->Transparent_color; LSDB.Aspect =0; // Palette normale // On sauve le LSDB dans le fichier @@ -2213,9 +2220,15 @@ void Save_GIF(T_IO_Context * context) current_layer++) { // Write a Graphic Control Extension - char GCE_block[] = "\x21\xF9\x04\x05\x05\x00\x00\x00"; - //if (Main_current_layer > 0) - // GCE_block[3] = '\x05'; + char GCE_block[] = "\x21\xF9\x04\x04\x05\x00\x00\x00"; + // 'Default' values: + // Disposal method "Do not dispose" + // Duration 5/100s (minimum viable value for current web browsers) + + if (current_layer > 0 || context->Background_transparent) + GCE_block[3] |= 1; // Transparent color flag + GCE_block[6] = context->Transparent_color; + Set_layer(context, current_layer); if (current_layer == context->Nb_layers -1) @@ -3231,6 +3244,9 @@ void Load_PNG(T_IO_Context * context) char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier byte png_header[8]; byte row_pointers_allocated; + png_bytep trans; + int num_trans; + png_color_16p trans_values; png_structp png_ptr; png_infop info_ptr; @@ -3388,11 +3404,24 @@ void Load_PNG(T_IO_Context * context) free(palette); palette = NULL; } - if (color_type != PNG_COLOR_TYPE_RGB && color_type != PNG_COLOR_TYPE_RGB_ALPHA) { Palette_loaded(context); } + // Transparency (tRNS) + if (png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values)) + { + int i; + for (i=0; iTransparent_color = i; + context->Background_transparent = 1; + break; + } + } + } context->Width=info_ptr->width; context->Height=info_ptr->height; @@ -3546,6 +3575,17 @@ void Save_PNG(T_IO_Context * context) } png_set_text(png_ptr, info_ptr, text_ptr, nb_text_chunks); } + if (context->Background_transparent) + { + // Transparency + byte opacity[256]; + // Need to fill a segment with '255', up to the transparent color + // which will have a 0. This piece of data (1 to 256 bytes) + // will be stored in the file. + memset(opacity, 255,context->Transparent_color); + opacity[context->Transparent_color]=0; + png_set_tRNS(png_ptr, info_ptr, opacity, (int)1 + context->Transparent_color,0); + } switch(Pixel_ratio) { case PIXEL_WIDE: diff --git a/fonts/GrafX2_Classic.gif b/fonts/GrafX2_Black.gif similarity index 82% rename from fonts/GrafX2_Classic.gif rename to fonts/GrafX2_Black.gif index af4d73c3923fc96b1a23405156862ef6f42a4a3e..221e3abb60305e165602535973964e724b9cc7fb 100644 GIT binary patch delta 83 zcmdnayPucU-P6s&aw97Tvy$RZ7MB1285ndJfWVKLlYyP%Kf^;A36FvW2bx&;m24JF nR%cF=U|=}6%r$y~?(NOom-(i63+Ue6R{r{#?T5`vnT41E=sFut delta 75 zcmV-R0JQ(V4Yv&iM@dFFH?ai>0~#y<0000^0|@{J2>$@#_!~%YpumCz4SVS0bPWh9z2%D5wEJUjWlof=0(B zEMX$64S@zxREQ7;5Rnv89jmhFhb#&Nh{3HO_z4a4Z~fo%X70T|&N*-9zVo~{Z}jjC z**47r(&1kyKmnjoOcrBfO^&Qd5XQqIh{-b5jH3~Hy&lJLtyZg6tCdQnOePbH#RwrT zm&<0enM@{~PN&gm7>1EZBmzJWfCFd&)Bs8V8Gsl70dN7>089Wn01W^GAOR2r==Ff( zpw)s}4N4`*WFQs;Lcrw$n+;4R(CI*<0fqr-QtqXw{%rf>H)DF^CZ$ zE^yhvW&)EAbQ;hwz(_E)A2J!IP_!;CY6io&_Y4k4#N)*Yh2atjOQBe=Qn_k0_N}c} zI^E=U2q5dp6rAFsbz!I(ECq{`!QqK`!Z@KMT%uqpRO?k5S52#ZtIkR{$p(T<)>A0B zi;I@QP_tMH4kv@h6A6WJ5=pr6omHy!8jWjftG!NVHDzzqUd*1^O2i*nhfziLTE1a9yIiD(cKYPsGvMBu))4;8r+O!DeLa za22noA`dK@Mh?bchZQi4c|eGY5CfqAgrX4=B9wuU5}_J|o*<+{h%hF}m_07n7;2r&64%*-dC3$xu6ol_$)wOmBcA&1lnEa$9n^|%;PFS2qBy`^}Y*KnR< za~K=l$=RIjXeXE0&fdQz)p<{*Sb9XhHQha=SCVqGU|TjlamGxaTMj$&f4XShqw+2E zm3!wpq*h4mw-#+LcB^mP9my*3t@R6(rqb?`<~@*a*muF{`OR-0&ys8*JGGY`AME|% zO<7(?b<(u*r;+Z4z{+3y7RjI6429n1+jwu(t8R3jNn1ITsw{gORxhzzHLguR7V($D z+ux0dE$vRZwqnc8 z_O{-P%&w}cJl^p~o%=+&zS%7fFCNWuj#5>9sEuq-w4}*ahwGjs_a(0VTru>b-Khaf zh?zM(h~HvT@GO3~tA0Te=~;5HuwZw1m(X@#q*L(K*zrz5=~8O$>F)SVA-`O(Xbwqf zE7no?&9`my&%S?Zo`23`xS`|h{8CNU;gmab{e_QqQiBg{$jZnU#K)-E{HL!q*&>HE zciK`nczNPc{o)%A96u;zD*Q0>GLvoWn zZJa%BQiq6G0V;yzN0Ai9W^^{PF~zV-hheOA@RM? zh}V~j{UVg->nhCb@-}v_UREA@$)9>6((kOkvcI$~C*5?RPw0iz;Y?axVV37x)x|Rd zh7_qGa&c5zW5e<)(^a1i9eM3#{_d(}imzJ`qKEWfBKbtyE23u#*TRykXTp{ z8`N?xN|ifPKiJllCu@%>jCT*banJf_|1xdFW%Wqyra2b=rw+M0mA_iH%Mc>Zx$8x( zqCd>^{9P0l`2EYBQMf~Az5Kh9{OEzQz4uH`wkx|=`8ImK*uEDZ>)~6EuPC~5WL8B& zjdjQJCf}iilMnfI53b!mXQQTfZ!PN^ZeqA)U+-y&9pd+NBs-6PWL%CKAJr9Pages->Transparent_color; + byte transparent_background = Main_backups->Pages->Background_transparent; + short clicked_button; + byte color; + byte click; + + Open_window(122,100,"Layers"); + + Window_display_frame_in( 6, 21,110, 52); + Print_in_window(14,18,"Transparency",MC_Dark,MC_Light); + + Print_in_window(11,38,"Color",MC_Black,MC_Light); + Window_set_normal_button(54, 36, 56,13,"" , 0,1,KEY_NONE); // 1 + Draw_transparent_color(transparent_color); + + Print_in_window(11,57,"Background",MC_Black,MC_Light); + Window_set_normal_button(95, 54, 15,13,"" , 0,1,KEY_NONE); // 2 + Draw_transparent_background(transparent_background); + + Window_set_normal_button( 7, 78, 51,14,"OK" , 0,1,SDLK_RETURN); // 3 + Window_set_normal_button(63, 78, 51,14,"Cancel", 0,1,KEY_ESC); // 4 + + Update_window_area(0,0,Window_width, Window_height); + + do + { + + clicked_button=Window_clicked_button(); + //if (Is_shortcut(Key,0x100+BUTTON_HELP)) + // Window_help(BUTTON_LAYERS, NULL); + switch(clicked_button) + { + case 1: // color + Get_color_behind_window(&color,&click); + if (click && transparent_color!=color) + { + transparent_color=color; + Hide_cursor(); + Draw_transparent_color(transparent_color); + Display_cursor(); + Wait_end_of_click(); + } + break; + + case 2: // background + transparent_background = !transparent_background; + Hide_cursor(); + Draw_transparent_background(transparent_background); + Display_cursor(); + break; + } + } + while (clicked_button<3); + + // On exit Hide_cursor(); + Close_window(); + if (clicked_button==3) + { + // Accept changes + if (Main_backups->Pages->Transparent_color != transparent_color || + Main_backups->Pages->Background_transparent != transparent_background) + { + Backup_layers(-1); + Main_backups->Pages->Transparent_color = transparent_color; + Main_backups->Pages->Background_transparent = transparent_background; + Redraw_layered_image(); + Display_all_screen(); + End_of_modification(); + } + } Unselect_button(BUTTON_LAYER_MENU); Display_cursor(); } diff --git a/loadsave.c b/loadsave.c index 6d2e1e31..2ced475d 100644 --- a/loadsave.c +++ b/loadsave.c @@ -179,6 +179,11 @@ void Set_pixel(T_IO_Context *context, short x_pos, short y_pos, byte color) // Chargement des pixels dans la preview case CONTEXT_PREVIEW: + // Skip pixels of transparent index if : + // - It's the first layer, and image has transparent background. + // - or it's a layer above the first one + if (color == context->Transparent_color && (context->Current_layer > 0 || context->Background_transparent)) + break; if (((x_pos % context->Preview_factor_X)==0) && ((y_pos % context->Preview_factor_Y)==0)) { if (context->Ratio == PIXEL_WIDE && @@ -375,6 +380,8 @@ void Pre_load(T_IO_Context *context, short width, short height, long file_size, context->Height = height; context->Ratio = ratio; context->Nb_layers = 1; + context->Transparent_color=0; + context->Background_transparent=0; switch(context->Type) { @@ -741,6 +748,10 @@ void Load_image(T_IO_Context *context) Main_current_layer = context->Nb_layers - 1; Main_layers_visible = (2<Pages->Transparent_color = context->Transparent_color; + Main_backups->Pages->Background_transparent = context->Background_transparent; // Correction des dimensions if (Main_image_width<1) @@ -1032,7 +1043,6 @@ void Init_context_preview(T_IO_Context * context, char *file_name, char *file_di context->File_name = file_name; context->File_directory = file_directory; context->Format = Main_fileformat; // FIXME ? - } /// Setup for loading/saving the current main image @@ -1050,6 +1060,7 @@ void Init_context_layered_image(T_IO_Context * context, char *file_name, char *f context->Nb_layers = Main_backups->Pages->Nb_layers; strcpy(context->Comment, Main_comment); context->Transparent_color=Main_backups->Pages->Transparent_color; + context->Background_transparent=Main_backups->Pages->Background_transparent; if (Pixel_ratio == PIXEL_WIDE || Pixel_ratio == PIXEL_WIDE2) context->Ratio=PIXEL_WIDE; else if (Pixel_ratio == PIXEL_TALL || Pixel_ratio == PIXEL_TALL2) @@ -1082,7 +1093,8 @@ void Init_context_brush(T_IO_Context * context, char *file_name, char *file_dire context->Height = Brush_height; context->Nb_layers = 1; // Solid save... could use BG color maybe - context->Transparent_color=-1; + context->Transparent_color=0; + context->Background_transparent=0; context->Ratio=PIXEL_SIMPLE; context->Target_address=Brush; context->Pitch=Brush_width; @@ -1102,7 +1114,8 @@ void Init_context_surface(T_IO_Context * context, char *file_name, char *file_di // context->Width // context->Height context->Nb_layers = 1; - context->Transparent_color=-1; + context->Transparent_color=0; + context->Background_transparent=0; context->Ratio=PIXEL_SIMPLE; //context->Target_address //context->Pitch @@ -1111,6 +1124,8 @@ void Init_context_surface(T_IO_Context * context, char *file_name, char *file_di /// Function to call when need to switch layers. void Set_layer(T_IO_Context *context, byte layer) { + context->Current_layer = layer; + if (context->Type == CONTEXT_MAIN_IMAGE) { // This awful thing is the part that happens on load diff --git a/loadsave.h b/loadsave.h index ec488fd1..2e56cdc3 100644 --- a/loadsave.h +++ b/loadsave.h @@ -56,7 +56,8 @@ typedef struct short Height; byte Nb_layers; char Comment[COMMENT_SIZE+1]; - short Transparent_color; + byte Background_transparent; + byte Transparent_color; /// Pixel ratio of the image enum PIXEL_RATIO Ratio; @@ -64,7 +65,10 @@ typedef struct byte *Target_address; /// Pitch: Difference of addresses between one pixel and the one just "below" it long Pitch; - + + /// Internal: during load, marks which layer is being loaded. + short Current_layer; + /// Internal: Used to mark truecolor images on loading. Only used by preview. //byte Is_truecolor; /// Internal: Temporary RGB buffer when loading 24bit images diff --git a/pages.c b/pages.c index 0c5ae407..7ba40e6d 100644 --- a/pages.c +++ b/pages.c @@ -76,6 +76,7 @@ T_Page * New_page(byte nb_layers) page->File_format=DEFAULT_FILEFORMAT; page->Nb_layers=nb_layers; page->Transparent_color=0; // Default transparent color + page->Background_transparent=0; page->Next = page->Prev = NULL; } return page; diff --git a/struct.h b/struct.h index c16f1ce6..413f5458 100644 --- a/struct.h +++ b/struct.h @@ -347,7 +347,8 @@ typedef struct T_Page byte File_format; ///< File format, in enum ::FILE_FORMATS struct T_Page *Next; ///< Pointer to the next backup struct T_Page *Prev; ///< Pointer to the previous backup - word Transparent_color; ///< Index of transparent color. -1 or 0 to 255. + byte Background_transparent; ///< Boolean, true if Layer 0 should have transparent pixels + byte Transparent_color; ///< Index of transparent color. 0 to 255. byte Nb_layers; ///< Number of layers byte * Image[0]; ///< Pixel data for the (first layer of) image. // No field after Image[] ! Dynamic layer allocation for Image[1], [2] etc.