Hello,
saving a bitmap and testing the possible combinations, using :
oDrawImg:SaveImage( cFilename, nExport )
the alphachannel will be lost.
Is there another solution, saving a painted image ( BMP or PNG ) with a included alphachannel ?
I think something from FREEIMAGE.dll is missing in class TImage.
Testing with sample : Testimg.prg
Load a alphablended BMP and change the button from JPG to BMP, to view the result :
@ 5, 28 BUTTON "Save" SIZE 50, 10 OF oDlg ;
ACTION ( oImage:SaveImage( "SAVED.BMP", 0, 25 ), MsgInfo( "saved as saved.bmp" ) )
The painting ( two merged alphablended bmp's ) :
The preview of the EXPORT-result ( with lost alpha-channel ) :
I can use NCONVERT for saving ( with possible resize ),
but it only saves the MAIN-images ( file ) without the painted / merged second one or any other paintings.
The alphachannel is saved as well with this solution.
cScript := '-quiet -o ' + cNewFile + ' -ratio -rtype lanczos -resize ' + ;
ALLTRIM(STR(nExpWidth)) + ' ' + ;
ALLTRIM(STR(nExpHeight)) + ' -overwrite ' + ALLTRIM(cImagepath) + cWorkfile
CursorWait()
WAITRUN ( "NConvert " + cScript, 0 )
Using a NON alphablended BMP as MAIN-image, works fine !
The painting ( a merged alphablended bmp on JPG ) :
The preview of the exported image( BMP with alpha-channel on JPG ) :
Best regards
Uwe
How to keep a alpha-channel, save and resize a bitmap
How to keep a alpha-channel, save and resize a bitmap
Last edited by ukoenig on Mon Jun 23, 2014 3:04 pm, edited 3 times in total.
Since 1995 ( the first release of FW 1.9 )
i work with FW.
If you have any questions about special functions, maybe i can help.
i work with FW.
If you have any questions about special functions, maybe i can help.
- Antonio Linares
- Site Admin
- Posts: 42425
- Joined: Thu Oct 06, 2005 5:47 pm
- Location: Spain
- Has thanked: 15 times
- Been thanked: 48 times
- Contact:
Re: How to keep a existing alpha-channel, saving a bitmap ?
Uwe,
I think that FWH function DibFromBitmap() may not be properly saving the alpha channel.
You can review its source code here:
source\winapi\dibbmp.c
I guess we will have to google about it, or maybe FreeImage has a function that may help us...
I think that FWH function DibFromBitmap() may not be properly saving the alpha channel.
You can review its source code here:
source\winapi\dibbmp.c
I guess we will have to google about it, or maybe FreeImage has a function that may help us...
Re: How to keep a existing alpha-channel, saving a bitmap ?
Antonio,
the freeimage-sections about transparent
( maybe something can be used ) :
FreeImage_GetTransparencyTable
1 4 8
DLL_API BYTE * DLL_CALLCONV FreeImage_GetTransparencyTable(FIBITMAP *dib);
Returns a pointer to the bitmap’s transparency table. Only palletised bitmaps
have a transparency table. High-color bitmaps store the transparency values
directly in the bitmap
bits. FreeImage_GetTransparencyTable returns NULL for these bitmaps.
FreeImage_SetTransparencyTable
1 4 8
DLL_API void DLL_CALLCONV FreeImage_SetTransparencyTable(FIBITMAP *dib, BYTE *table,
int count);
Set the bitmap’s transparency table. Only palletised bitmaps have a transparency table.
Highcolor bitmaps store the transparency values directly in the bitmap bits.
FreeImage_SetTransparencyTable does nothing for these bitmaps.
#include "FreeImage.h"
int main(int argc, char* argv[]) {
FIBITMAP *hDIB24bpp = FreeImage_Load(FIF_BMP, "test.bmp", 0);
if (hDIB24bpp) {
// color-quantize 24bpp (results in a 8bpp bitmap to set transparency)
FIBITMAP *hDIB8bpp = FreeImage_ColorQuantize(hDIB24bpp, FIQ_WUQUANT);
// get palette and find bright green
RGBQUAD *Palette = FreeImage_GetPalette(hDIB8bpp);
BYTE Transparency[256];
for (unsigned i = 0; i < 256; i++) {
Transparency[i] = 0xFF;
if (Palette[i].rgbGreen >= 0xFE &&
Palette[i].rgbBlue == 0x00 &&
Palette[i].rgbRed == 0x00) {
Transparency[i] = 0x00;
}
}
// set the tranparency table
FreeImage_SetTransparencyTable(hDIB8bpp, Transparency, 256);
// save 8bpp image as transparent PNG
FreeImage_Save(FIF_PNG, hDIB8bpp, "test.png", 0);
FreeImage_Unload(hDIB24bpp);
FreeImage_Unload(hDIB8bpp);
}
return 0;
}
FreeImage_SetTransparent
1 4 8 32
DLL_API void DLL_CALLCONV FreeImage_SetTransparent(FIBITMAP *dib, BOOL enabled);
Tells FreeImage if it should make use of the transparency table or
the alpha channel that may accompany a bitmap. When calling this function with a
bitmap whose bitdepth is different from
1-, 4-, 8- or 32-bit, transparency is disabled whatever the value of the Boolean parameter.
FreeImage_IsTransparent
DLL_API BOOL DLL_CALLCONV FreeImage_IsTransparent(FIBITMAP *dib);
Returns TRUE when the transparency table is enabled (1-, 4- or 8-bit images) or when the
input dib contains alpha values (32-bit images, RGBA16 or RGBAF images). Returns FALSE
otherwise.
FreeImage_SetTransparentIndex
best regards
Uwe
the freeimage-sections about transparent
( maybe something can be used ) :
FreeImage_GetTransparencyTable
1 4 8
DLL_API BYTE * DLL_CALLCONV FreeImage_GetTransparencyTable(FIBITMAP *dib);
Returns a pointer to the bitmap’s transparency table. Only palletised bitmaps
have a transparency table. High-color bitmaps store the transparency values
directly in the bitmap
bits. FreeImage_GetTransparencyTable returns NULL for these bitmaps.
FreeImage_SetTransparencyTable
1 4 8
DLL_API void DLL_CALLCONV FreeImage_SetTransparencyTable(FIBITMAP *dib, BYTE *table,
int count);
Set the bitmap’s transparency table. Only palletised bitmaps have a transparency table.
Highcolor bitmaps store the transparency values directly in the bitmap bits.
FreeImage_SetTransparencyTable does nothing for these bitmaps.
#include "FreeImage.h"
int main(int argc, char* argv[]) {
FIBITMAP *hDIB24bpp = FreeImage_Load(FIF_BMP, "test.bmp", 0);
if (hDIB24bpp) {
// color-quantize 24bpp (results in a 8bpp bitmap to set transparency)
FIBITMAP *hDIB8bpp = FreeImage_ColorQuantize(hDIB24bpp, FIQ_WUQUANT);
// get palette and find bright green
RGBQUAD *Palette = FreeImage_GetPalette(hDIB8bpp);
BYTE Transparency[256];
for (unsigned i = 0; i < 256; i++) {
Transparency[i] = 0xFF;
if (Palette[i].rgbGreen >= 0xFE &&
Palette[i].rgbBlue == 0x00 &&
Palette[i].rgbRed == 0x00) {
Transparency[i] = 0x00;
}
}
// set the tranparency table
FreeImage_SetTransparencyTable(hDIB8bpp, Transparency, 256);
// save 8bpp image as transparent PNG
FreeImage_Save(FIF_PNG, hDIB8bpp, "test.png", 0);
FreeImage_Unload(hDIB24bpp);
FreeImage_Unload(hDIB8bpp);
}
return 0;
}
FreeImage_SetTransparent
1 4 8 32
DLL_API void DLL_CALLCONV FreeImage_SetTransparent(FIBITMAP *dib, BOOL enabled);
Tells FreeImage if it should make use of the transparency table or
the alpha channel that may accompany a bitmap. When calling this function with a
bitmap whose bitdepth is different from
1-, 4-, 8- or 32-bit, transparency is disabled whatever the value of the Boolean parameter.
FreeImage_IsTransparent
DLL_API BOOL DLL_CALLCONV FreeImage_IsTransparent(FIBITMAP *dib);
Returns TRUE when the transparency table is enabled (1-, 4- or 8-bit images) or when the
input dib contains alpha values (32-bit images, RGBA16 or RGBAF images). Returns FALSE
otherwise.
FreeImage_SetTransparentIndex
best regards
Uwe
Since 1995 ( the first release of FW 1.9 )
i work with FW.
If you have any questions about special functions, maybe i can help.
i work with FW.
If you have any questions about special functions, maybe i can help.
Re: How to keep a existing alpha-channel, saving a bitmap ?
Hello Uwe,
I am also in this "film" (few days) and I try to load transparent patern "input.png" on dialog, put some text on it and save to "output.png". I found this modified tImage example which save PNG corectly, but when I try to put some text on bitmap and save, nothing changed on "output.png". I saw, that function FISAVEIMG do not save image from screen, but input.png loaded from disk convert to output.png:
*--------------------------------------------------------------------------------------------------------------------------------
hDib = FILOAD( nSrcFormat, cSrcFile, 0 ) // load "input.png" !!??
lOk = FISAVE( nDstFormat, hDib, cDstFile, 0 ) // when PNG is loaded from disk, save to "output.png" is OK.
*--------------------------------------------------------------------------------------------------------------------------------
I don't have your skils in graphic programing, but function FISAVE must be changed, to save modified bitmap from screen.
I am also in this "film" (few days) and I try to load transparent patern "input.png" on dialog, put some text on it and save to "output.png". I found this modified tImage example which save PNG corectly, but when I try to put some text on bitmap and save, nothing changed on "output.png". I saw, that function FISAVEIMG do not save image from screen, but input.png loaded from disk convert to output.png:
*--------------------------------------------------------------------------------------------------------------------------------
hDib = FILOAD( nSrcFormat, cSrcFile, 0 ) // load "input.png" !!??
lOk = FISAVE( nDstFormat, hDib, cDstFile, 0 ) // when PNG is loaded from disk, save to "output.png" is OK.
*--------------------------------------------------------------------------------------------------------------------------------
I don't have your skils in graphic programing, but function FISAVE must be changed, to save modified bitmap from screen.
Code: Select all | Expand
#include "FiveWin.ch"
#include "Constant.ch"
#include "Inkey.ch"
#define GW_CHILD 5
#define GW_HWNDNEXT 2
#define RT_BITMAP 2
#ifdef __XPP__
#define New _New
#define Super ::TBitmap
#endif
STATIC hLib
FUNCTION MAIN()
LOCAL oDlg, oImg
DEFINE DIALOG oDlg;
SIZE 700, 500
* @ 1, 1 IMAGE oImg FILE "input.png" of oDlg ADJUST
@ 40, 20 IMAGE oImg SIZE 300, 200 OF oDlg FILENAME NIL PIXEL SCROLL
///////////////////////////////////////////////////////////////////////////////////////
oImg:lTransparent := .t.
oImg:LoadImage( , "input.png" )
oImg:lTransparent := .t.
oImg:bPainted = { || SetBkMode( oImg:hDC, 1 ),;
SetTextColor( oImg:hDC, CLR_WHITE ),;
TextOut( oImg:hDC, 5, 15, time() ) }
///////////////////////////////////////////////////////////////////////////////////////
@ 0, 1 BUTTON "Save" ACTION MsgInfo( oImg:SaveImage( "output.png", 13 ) )
@ 0, 7 BUTTON "Print" ACTION PRINT( oImg )
ACTIVATE DIALOG oDlg CENTER
RETURN NIL
STATIC FUNCTION PRINT( oImg )
LOCAL oPrn
PRINT oPrn PREVIEW
PAGE
oPrn:SayImage( 0, 0, oImg )
ENDPAGE
ENDPRINT
RETURN NIL
//----------------------------------------------------------------------------//
CLASS TImage FROM TBitmap
CLASSDATA lRegistered AS LOGICAL
METHOD New( nTop, nLeft, nWidth, nHeight, cResName, cBmpFile, lNoBorder,;
oWnd, bLClicked, bRClicked, lScroll, lStretch, oCursor,;
cMsg, lUpdate, bWhen, lPixel, bValid, lDesign ) CONSTRUCTOR
METHOD Define( cResName, cBmpFile, oWnd ) CONSTRUCTOR
METHOD LoadImage( cResName, cBmpFile )
METHOD SaveImage( cFile, nFormat, nFlag )
ENDCLASS
//----------------------------------------------------------------------------//
METHOD New( nTop, nLeft, nWidth, nHeight, cResName, cBmpFile, lNoBorder,;
oWnd, bLClicked, bRClicked, lScroll, lStretch, oCursor,;
cMsg, lUpdate, bWhen, lPixel, bValid, lDesign ) CLASS TImage
#ifdef __XPP__
::lRegistered = .f.
#endif
Super:New( nTop, nLeft, nWidth, nHeight, cResName, cBmpFile, lNoBorder, ;
oWnd, bLClicked, bRClicked, lScroll, lStretch, oCursor, ;
cMsg, lUpdate, bWhen, lPixel, bValid, lDesign )
return Self
//----------------------------------------------------------------------------//
// This method does not create a control, it just creates a bitmap object to
// be used somewhere else.
METHOD Define( cResName, cBmpFile, oWnd ) CLASS TImage
local aBmpPal
DEFAULT oWnd := GetWndDefault()
::oWnd = oWnd
::nZoom = 1
::hWnd = 0
::hBitmap = 0
::hPalette = 0
if ! Empty( cResName )
aBmpPal = PalBmpLoad( cResName )
::hBitmap = aBmpPal[ 1 ]
::hPalette = aBmpPal[ 2 ]
cBmpFile = nil
endif
if ! Empty( cBmpFile ) .and. File( cBmpFile )
::cBmpFile = cBmpFile
::hBitmap = FILoadImg( AllTrim( cBmpFile ) )
endif
if ::hBitmap != 0
PalBmpNew( 0, ::hBitmap, ::hPalette )
endif
return Self
//----------------------------------------------------------------------------//
METHOD LoadImage( cResName, cBmpFile ) CLASS TImage
local lChanged := .f.
local hOldBmp := ::hBitmap
local hOldPal := ::hPalette
local aBmpPal
DEFAULT cResName := ::cResName, cBmpFile := ::cBmpFile
if ! Empty( cResName )
aBmpPal = PalBmpLoad( cResName )
::hBitmap = aBmpPal[ 1 ]
::hPalette = aBmpPal[ 2 ]
lChanged = .t.
cBmpFile = nil
elseif File( cBmpFile )
::hBitmap = FILoadImg( AllTrim( cBmpFile ) )
lChanged := .t.
cResName := nil
endif
if lChanged
::cResName = cResName
::cBmpFile = cBmpFile
if ! Empty( hOldBmp )
PalBmpFree( hOldBmp, hOldPal )
endif
PalBmpNew( ::hWnd, ::hBitmap, ::hPalette )
endif
return lChanged
//----------------------------------------------------------------------------//
METHOD SaveImage( cFile, nFormat ) CLASS TImage
// 0 -> Bmp
// 2 -> Jpg
// 13 -> Png
return FISaveImg( ::cBmpFile, cFile, nFormat )
//----------------------------------------------------------------------------//
#define CBM_INIT 4
#define DIB_RGB_COLORS 0
FUNCTION FILOADIMG( cFile )
LOCAL nFormat, hDib, hInfoH, hInfo, hBits, hWnd, hDC, hBmp
#ifdef __CLIPPER__
hLib = LOADLIB32( "freeimage.dll" )
#else
hLib = LOADLIBRARY( "freeimage.dll" )
#endif
if hLib <= 32
MsgStop( "Cannot load FreeImage.dll" )
return 0
endif
nFormat = FIGETFILETYPE( cFile, 0 )
hDib = FILOAD( nFormat, cFile, 0 )
hInfoH = FIGETINFOHEADER( hDib )
hInfo = FIGETINFO( hDib )
hBits = FIGETBITS( hDib )
hWnd = GETDESKTOPWINDOW()
#ifdef __CLIPPER__
hDC = GETDC32( hWnd )
#else
hDC = GETDC( hWnd )
#endif
hBmp = CREATEDIBITMAP( hDC, hInfoH, CBM_INIT, hBits, hInfo, DIB_RGB_COLORS )
#ifdef __CLIPPER__
RELEASEDC32( hWnd, hDC )
#else
RELEASEDC( hWnd, hDC )
#endif
FIUNLOAD( hDib )
#ifdef __CLIPPER__
FREELIB32( hLib )
#else
FREELIBRARY( hLib )
#endif
#ifdef __CLIPPER__
hBmp = NLOWORD( WOWHANDLE16( hBmp, 8 ) )
#endif
RETURN hBmp
FUNCTION FISAVEIMG( cSrcFile, cDstFile, nDstFormat )
LOCAL nSrcFormat, hDib, lOk
#ifdef __CLIPPER__
hLib = LOADLIB32( "freeimage.dll" )
#else
hLib = LOADLIBRARY( "freeimage.dll" )
#endif
nSrcFormat = FIGETFILETYPE( cSrcFile, 0 )
hDib = FILOAD( nSrcFormat, cSrcFile, 0 )
lOk = FISAVE( nDstFormat, hDib, cDstFile, 0 )
#ifdef __CLIPPER__
FREELIB32( hLib )
#else
FREELIBRARY( hLib )
#endif
RETURN lOk
//----------------------------------------------------------------------------//
DLL32 STATIC FUNCTION FIGETFILETYPE( cFileName AS LPSTR, nSize AS LONG ) AS LONG;
PASCAL FROM "_FreeImage_GetFileType@8" LIB hLib
DLL32 STATIC FUNCTION FILOAD( nFormat AS LONG, cFileName AS LPSTR, nFlags AS LONG ) AS LONG;
PASCAL FROM "_FreeImage_Load@12" LIB hLib
DLL32 STATIC FUNCTION FISAVE( nFormat AS LONG, hDib AS LONG, cFileName AS LPSTR, nFlags AS LONG ) AS BOOL;
PASCAL FROM "_FreeImage_Save@16" LIB hLib
DLL32 STATIC FUNCTION FIUNLOAD( hDib AS LONG ) AS VOID;
PASCAL FROM "_FreeImage_Unload@4" LIB hLib
DLL32 STATIC FUNCTION FIGETINFOHEADER( hDib AS LONG ) AS LONG;
PASCAL FROM "_FreeImage_GetInfoHeader@4" LIB hLib
DLL32 STATIC FUNCTION FIGETINFO( hDib AS LONG ) AS LONG;
PASCAL FROM "_FreeImage_GetInfo@4" LIB hLib
DLL32 STATIC FUNCTION FIGETBITS( hDib AS LONG ) AS LONG;
PASCAL FROM "_FreeImage_GetBits@4" LIB hLib
DLL32 STATIC FUNCTION GETDC32( hWnd AS LONG ) AS LONG;
PASCAL FROM "GetDC" LIB "user32.dll"
DLL32 STATIC FUNCTION RELEASEDC32( hWnd AS LONG ) AS LONG;
PASCAL FROM "ReleaseDC" LIB "user32.dll"
DLL32 STATIC FUNCTION CREATEDIBITMAP( hDC AS LONG, hInfoH AS LONG, nFlags AS LONG, hBits AS LONG, hInfo AS LONG, nUsage AS LONG ) AS LONG;
PASCAL FROM "CreateDIBitmap" LIB "gdi32.dll"
DLL32 FUNCTION WOWHANDLE16( nHandle AS LONG, nHandleType AS LONG ) AS LONG;
PASCAL FROM "WOWHandle16" LIB "wow32.dll"
//----------------------------------------------------------------------------//
Boris (FWH 20.07, xHarbour 1.2.3, Harbour 3.2.0, BCC74, MySql 5.7)
Re: How to keep a existing alpha-channel, saving a bitmap ?
Just a little change in class TImage ( nothing new to be included ) and it works :
( I will add the source of a new sample )
I still have to test, saving a resized image.
The loaded alphablended BMP using sample TESTIMG.prg
The result of the saved BMP with a still existing alpha-channel
before, there was a black background
Alphablended works ONLY with 32 bpp !!!
We can check, if there is a alpha-channel
if NO = hDib2 = FICNV24( hDib )
if YES = hDib2 = FICONVTO32( hDib )
the needed changes in class TImage :
METHOD SaveImage( cFile, nFormat, nQuality ) CLASS TImage
local hDib := DibFromBitmap( ::hBitmap, ::hPalette )
local cTempFile := cTempFile()
local lSaved, lAlpha := ::HasAlpha()
DibWrite( cTempFile, hDib )
GloBalFree( hDib )
lSaved = FIConvertImageFile( cTempFile, cFile, nFormat, nQuality, lAlpha )
FErase( cTempFile )
return lSaved
//----------
function FIConvertImageFile( cSrcFile, cDstFile, nDstFormat, nQuality, lAlpha )
local nSrcFormat, hDib, hDib2, lOk := .f.
DEFAULT nQuality := 0
if LoadFreeImage() > 32
nSrcFormat = FIGETFILETYPE( cSrcFile, 0 )
hDib = FILOAD( nSrcFormat, cSrcFile, 0 )
if lAlpha
hDib2 = FICONVTO32( hDib )
else
hDib2 = FICNV24( hDib )
endif
lOk = FISAVE( nDstFormat, hDib2, cDstFile, nQuality )
endif
return lOk
The results of ALPHA ON / OFF
Now it is possible, to keep the alpha-channel on a resized image !
@ 110, 230 BUTTON "Save resized" SIZE 50, 10 OF oDlg PIXEL FONT oFont1 ;
ACTION IIF( !Empty(gcFile), ( hBmp := oImage:hBitmap, ;
oImage:hBitmap := ResizeImg( hBmp, nExpWidth, nExpHeight ), ;
DeleteObject( hBmp ), ;
oImage:SaveImage( c_path2 + "SAVED.BMP", 0, 25 ), ;
MsgInfo( "saved as saved.bmp" ) ), ;
MsgAlert( "NO image to save !", "Error" ) )
Another test with these changes : make color transparent :
A PNG - test
best regards
Uwe
( I will add the source of a new sample )
I still have to test, saving a resized image.
The loaded alphablended BMP using sample TESTIMG.prg
The result of the saved BMP with a still existing alpha-channel
before, there was a black background
Alphablended works ONLY with 32 bpp !!!
We can check, if there is a alpha-channel
if NO = hDib2 = FICNV24( hDib )
if YES = hDib2 = FICONVTO32( hDib )
the needed changes in class TImage :
METHOD SaveImage( cFile, nFormat, nQuality ) CLASS TImage
local hDib := DibFromBitmap( ::hBitmap, ::hPalette )
local cTempFile := cTempFile()
local lSaved, lAlpha := ::HasAlpha()
DibWrite( cTempFile, hDib )
GloBalFree( hDib )
lSaved = FIConvertImageFile( cTempFile, cFile, nFormat, nQuality, lAlpha )
FErase( cTempFile )
return lSaved
//----------
function FIConvertImageFile( cSrcFile, cDstFile, nDstFormat, nQuality, lAlpha )
local nSrcFormat, hDib, hDib2, lOk := .f.
DEFAULT nQuality := 0
if LoadFreeImage() > 32
nSrcFormat = FIGETFILETYPE( cSrcFile, 0 )
hDib = FILOAD( nSrcFormat, cSrcFile, 0 )
if lAlpha
hDib2 = FICONVTO32( hDib )
else
hDib2 = FICNV24( hDib )
endif
lOk = FISAVE( nDstFormat, hDib2, cDstFile, nQuality )
endif
return lOk
The results of ALPHA ON / OFF
Now it is possible, to keep the alpha-channel on a resized image !
@ 110, 230 BUTTON "Save resized" SIZE 50, 10 OF oDlg PIXEL FONT oFont1 ;
ACTION IIF( !Empty(gcFile), ( hBmp := oImage:hBitmap, ;
oImage:hBitmap := ResizeImg( hBmp, nExpWidth, nExpHeight ), ;
DeleteObject( hBmp ), ;
oImage:SaveImage( c_path2 + "SAVED.BMP", 0, 25 ), ;
MsgInfo( "saved as saved.bmp" ) ), ;
MsgAlert( "NO image to save !", "Error" ) )
Another test with these changes : make color transparent :
A PNG - test
best regards
Uwe
Since 1995 ( the first release of FW 1.9 )
i work with FW.
If you have any questions about special functions, maybe i can help.
i work with FW.
If you have any questions about special functions, maybe i can help.
- Antonio Linares
- Site Admin
- Posts: 42425
- Joined: Thu Oct 06, 2005 5:47 pm
- Location: Spain
- Has thanked: 15 times
- Been thanked: 48 times
- Contact:
Re: How to keep a alpha-channel, save and resize a bitmap
Uwe,
Excellent!
You are a real master using images, thanks!
Excellent!
You are a real master using images, thanks!