Drawing on a TImage and save [Solved]

Drawing on a TImage and save [Solved]

Postby Enrico Maria Giordano » Sun Mar 30, 2014 6:13 pm

Dear friends, I need to draw on a TImage control and save the result. I already tried using SetPixel() on TImage hDC but it saves the original image without my new drawings. This is a sample:

Code: Select all  Expand view
#include "Fivewin.ch"


FUNCTION MAIN()

    LOCAL oDlg, oImg

    DEFINE DIALOG oDlg;
           SIZE 800, 600

    @ 0, 0 IMAGE oImg;
           FILE "TEST.JPG"

    @ 15, 0 BUTTON "Draw";
            ACTION DRAWIMG( oImg )

    @ 15, 20 BUTTON "Save";
             ACTION oImg:SaveImage( "MYIMAGETEST.JPG", 2 )

    ACTIVATE DIALOG oDlg;
             CENTER

    RETURN NIL


STATIC FUNCTION DRAWIMG( oImg )

    LOCAL hDC := oImg:GetDC()

    LOCAL x, y

    FOR y = 10 TO 50
        FOR x = 10 TO 50
            SETPIXEL( hDC, x, y, CLR_HRED )
        NEXT
    NEXT

    oImg:ReleaseDC()

    RETURN NIL


Any ideas?

Thank you in advance.

EMG
User avatar
Enrico Maria Giordano
 
Posts: 8710
Joined: Thu Oct 06, 2005 8:17 pm
Location: Roma - Italia

Re: Drawing on a TImage and save

Postby cnavarro » Sun Mar 30, 2014 9:33 pm

Enrico
I understand what you're trying, but I have not found a simple way
I used a function of Daniel Garcia-Gil found in this forum but I make the bitmap in black
I modified the function found in Microsoft MSDN and running, but my knowledge does not allow me to save the file as JPG and BMP only as

Entiendo lo que intentas, pero no he encontrado una forma sencilla
He usado una function de Daniel Garcia-Gil encontrada en este foro pero me crea el bitmap en negro
He modificado la function encontrada en el MSDN de Microsoft y funciona correctamente, pero mis conocimientos no me permiten guardar el fichero como JPG y solo como BMP

Code: Select all  Expand view

#include "Fivewin.ch"

#define SRCCOPY          0x00CC0020
#define SM_CXSCREEN      0
#define SM_CYSCREEN      1

#define HALFTONE  4

FUNCTION MAIN()

    LOCAL oDlg, oImg

    DEFINE DIALOG oDlg;
           SIZE 800, 600

    @ 0, 0 IMAGE oImg;
           FILE "WORD.JPG" OF oDlg

    @ 15, 5 BUTTON "Draw";
            ACTION ( DRAWIMG( oImg ) ) //, oImg:Refresh() )
           
    @ 15, 25 BUTTON "Save FW";
             ACTION SaveMiBmp( oDlg, oImg:nTop, oImg:nLeft, ;
                         oImg:nWidth, oImg:nHeight, "IMAGENFW.BMP" ) //.JPG" )
            //ACTION oImg:SaveImage( "IMGENFW.JPG", 2 )


    @ 15, 40 BUTTON "Save C";
             ACTION CaptureImage( oDlg:hWnd, oImg:nTop, oImg:nLeft, ;
                    oImg:nWidth, oImg:nHeight, "IMAGENC.BMP" )

    @ 15, 55 BUTTON "Exit" ACTION oDlg:End()

    ACTIVATE DIALOG oDlg;
             CENTER

    RETURN NIL


STATIC FUNCTION DRAWIMG( oImg )

    LOCAL hDC := oImg:GetDC()
    Local uImg

    LOCAL x, y

    FOR y = 10 TO 50
        FOR x = 10 TO 50
            SETPIXEL( hDC, x, y, CLR_HRED )
        NEXT
    NEXT

    oImg:ReleaseDC()
RETURN uImg

//-----------------------------------------------------------------------------
//http://forums.fivetechsupport.com/viewtopic.php?f=6&t=19403&p=137661&hilit=SaveToBmp#p102241
// SaveToBmp2 de Daniel Garcia-Gil con modificaciones
// Cristobal Navarro
//-----------------------------------------------------------------------------

Function SaveMiBmp( oWnd, nTop, nLeft, nWidth, nHeight, cBmpFile )

   local hParDC   := oWnd:GetDC()
   local hBmp
   local hOldBmp
   local hDib
   local hDC      := CreateCompatibleDC( hParDC )

    //This is the best stretch mode
    SetStretchBltMode(hParDC,HALFTONE)

    //The source DC is the entire screen and the destination DC is the current window (HWND)
    StretchBlt(hParDC,;
               0,0,;
               nWidth, nHeight,;
               hDC,;
               0,0,;
               GetSysMetrics( nWidth - nLeft ),;  //GetSystemMetrics (SM_CXSCREEN),
               GetSysMetrics( nHeight - nTop ),;  //GetSystemMetrics (SM_CYSCREEN),
               SRCCOPY)

   hBmp      := CreateCompatibleBitmap( hDC, nWidth, nHeight )
   hOldBmp   := SelectObject( hDC, hBmp )

   BitBlt( hDC, 0, 0, nWidth, nHeight, hParDC, 0, 0, SRCCOPY )

   SelectObject( hDC, hOldBmp )
   DeleteDC( hDC )
   hDib = DibFromBitmap( hBmp )
   DibWrite( cBmpFile, hDib )
   GloBalFree( hDib )
   DeleteObject( hBmp )
   oWnd:ReleaseDC()  

Return ( File( cBmpFile ) )

//-----------------------------------------------------------------------------
// Daniel Garcia - Gil  -  Original
//http://forums.fivetechsupport.com/viewtopic.php?f=6&t=19403&p=137661&hilit=SaveToBmp#p102241
//-----------------------------------------------------------------------------

Function SaveToBmp2( oWnd, cBmpFile )
   
   local hDeskDC := GetDC( GetDesktopWindow() )
   local hDC  := CreateCompatibleDC( hDeskDC )
   local hOldBmp
   local hDib
   local hBmp
   local nWidth //:= GetSysMetrics( SM_CXSCREEN )
   local nHeight //:= GetSysMetrics( SM_CYSCREEN )
   
     
   hBmp = CreateCompatibleBitmap( hDeskDC, nWidth, nHeight )

   hOldBmp = SelectObject( hDC, hBmp )
   
   // No // PrintWindow( oWnd:hWnd, hDC )
   
   BitBlt( hDC, 0, 0, nWidth, nHeight, hDeskDC, 0, 0, SRCCOPY )
   
   SelectObject( hDC, hOldBmp )
   DeleteDC( hDC )
   hDib = DibFromBitmap( hBmp )
   DibWrite( cBmpFile, hDib )
   GloBalFree( hDib )
   DeleteObject( hBmp )

return ( File( cBmpFile ) )
 
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

#pragma BEGINDUMP

//#define STRICT
#include "stdafx.h"
#include "windows.h"
#include "hbapi.h"

//-----------------------------------------------------------------------------
//http://msdn.microsoft.com/en-us/library/windows/desktop/dd183402(v=vs.85).aspx
// Modificada por Cristobal Navarro
//-----------------------------------------------------------------------------

int CaptureAnImage(HWND hWnd,
                   int nTop, int nLeft,  
                   int nW , int nH , LPCTSTR pszFichero )
{
    HDC hdcScreen;
    HDC hdcWindow;
    HDC hdcMemDC = NULL;
    HBITMAP hbmScreen = NULL;
    BITMAP bmpScreen;

    // Retrieve the handle to a display device context for the client
    // area of the window.
    hdcScreen = GetDC(NULL);
    hdcWindow = GetDC(hWnd);

    // Create a compatible DC which is used in a BitBlt from the window DC
    hdcMemDC = CreateCompatibleDC(hdcWindow);

    if(!hdcMemDC)
    {
        MessageBox(hWnd, TEXT("CreateCompatibleDC has failed"), TEXT("Failed"), MB_OK);
        goto done;
    }

    // Get the client area for size calculation
    RECT rcClient;
    rcClient.top = nTop; //0;
        rcClient.left = nLeft; //0;
        rcClient.right = nW; //200;
        rcClient.bottom = nH; //100;

    //GetWindowRect(hWnd, &rcClient );
    //GetClientRect(hWnd, &rcClient );

    //This is the best stretch mode
    SetStretchBltMode(hdcWindow,HALFTONE);

    //The source DC is the entire screen and the destination DC is the current window (HWND)
    if(!StretchBlt(hdcWindow,
               0,0,
               rcClient.right, rcClient.bottom,
               hdcScreen,
               0,0,
               GetSystemMetrics( rcClient.right - rcClient.left ),  //GetSystemMetrics (SM_CXSCREEN),
               GetSystemMetrics( rcClient.bottom - rcClient.top ),  //GetSystemMetrics (SM_CYSCREEN),
               SRCCOPY))
    {
        MessageBox(hWnd, TEXT("StretchBlt has failed"),TEXT("Failed"), MB_OK);
        goto done;
    }
   
    // Create a compatible bitmap from the Window DC
    hbmScreen = CreateCompatibleBitmap(hdcWindow, rcClient.right-rcClient.left, rcClient.bottom-rcClient.top);
   
    if(!hbmScreen)
    {
        MessageBox(hWnd, TEXT("CreateCompatibleBitmap Failed"),TEXT("Failed"), MB_OK);
        goto done;
    }

    // Select the compatible bitmap into the compatible memory DC.
    SelectObject(hdcMemDC,hbmScreen);
   
    // Bit block transfer into our compatible memory DC.
    if(!BitBlt(hdcMemDC,
               0,0,
               rcClient.right-rcClient.left,
               rcClient.bottom-rcClient.top,
               hdcWindow,
               0,0,
               SRCCOPY))
    {
        MessageBox(hWnd, TEXT("BitBlt has failed"), TEXT("Failed"), MB_OK);
        goto done;
    }

    // Get the BITMAP from the HBITMAP
    GetObject(hbmScreen,sizeof(BITMAP),&bmpScreen);
     
    BITMAPFILEHEADER   bmfHeader;    
    BITMAPINFOHEADER   bi;
     
    bi.biSize = sizeof(BITMAPINFOHEADER);    
    bi.biWidth = bmpScreen.bmWidth;    
    bi.biHeight = bmpScreen.bmHeight;  
    bi.biPlanes = 1;    
    bi.biBitCount = 32;    
    bi.biCompression = BI_RGB;    
    bi.biSizeImage = 0;  
    bi.biXPelsPerMeter = 0;    
    bi.biYPelsPerMeter = 0;    
    bi.biClrUsed = 0;    
    bi.biClrImportant = 0;

    DWORD dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpScreen.bmHeight;

    // Starting with 32-bit Windows, GlobalAlloc and LocalAlloc are implemented as wrapper functions that
    // call HeapAlloc using a handle to the process's default heap. Therefore, GlobalAlloc and LocalAlloc
    // have greater overhead than HeapAlloc.
    HANDLE hDIB = GlobalAlloc(GHND,dwBmpSize);
    char *lpbitmap = (char *)GlobalLock(hDIB);    

    // Gets the "bits" from the bitmap and copies them into a buffer
    // which is pointed to by lpbitmap.
    GetDIBits(hdcWindow, hbmScreen, 0,
        (UINT)bmpScreen.bmHeight,
        lpbitmap,
        (BITMAPINFO *)&bi, DIB_RGB_COLORS);

    // A file is created, this is where we will save the screen capture.
    HANDLE hFile = CreateFile( pszFichero , //TEXT("capture.bmp"),
        GENERIC_WRITE,
        0,
        NULL,
        CREATE_ALWAYS,
        FILE_ATTRIBUTE_NORMAL, NULL);  
   
    // Add the size of the headers to the size of the bitmap to get the total file size
    DWORD dwSizeofDIB = dwBmpSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
 
    //Offset to where the actual bitmap bits start.
    bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);
   
    //Size of the file
    bmfHeader.bfSize = dwSizeofDIB;
   
    //bfType must always be BM for Bitmaps
    bmfHeader.bfType = 0x4D42; //BM  
 
    DWORD dwBytesWritten = 0;
    WriteFile(hFile, (LPSTR)&bmfHeader, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL);
    WriteFile(hFile, (LPSTR)&bi, sizeof(BITMAPINFOHEADER), &dwBytesWritten, NULL);
    WriteFile(hFile, (LPSTR)lpbitmap, dwBmpSize, &dwBytesWritten, NULL);
   
    //Unlock and Free the DIB from the heap
    GlobalUnlock(hDIB);    
    GlobalFree(hDIB);

    //Close the handle for the file that was created
    CloseHandle(hFile);
       
    //Clean up
done:
    DeleteObject(hbmScreen);
    DeleteObject(hdcMemDC);
    ReleaseDC(NULL,hdcScreen);
    ReleaseDC(hWnd,hdcWindow);

    return 0;
}


HB_FUNC( CAPTUREIMAGE )
{
  CaptureAnImage( (HWND) hb_parnl( 1 ), hb_parnl( 2 ), hb_parnl( 3 ),
                   hb_parnl( 4 ), hb_parnl( 5 ), hb_parc( 6 ) ) ;
}


#pragma ENDDUMP


 
Cristobal Navarro
Hay dos tipos de personas: las que te hacen perder el tiempo y las que te hacen perder la noción del tiempo
El secreto de la felicidad no está en hacer lo que te gusta, sino en que te guste lo que haces
User avatar
cnavarro
 
Posts: 6541
Joined: Wed Feb 15, 2012 8:25 pm
Location: España

Re: Drawing on a TImage and save

Postby Enrico Maria Giordano » Sun Mar 30, 2014 9:45 pm

Cristobal,

cnavarro wrote:Enrico
I understand what you're trying, but I have not found a simple way


I can't compile your sample, sorry. I'm searching for an easier way... :-)

EMG
User avatar
Enrico Maria Giordano
 
Posts: 8710
Joined: Thu Oct 06, 2005 8:17 pm
Location: Roma - Italia

Re: Drawing on a TImage and save

Postby cnavarro » Sun Mar 30, 2014 9:46 pm

This tested with VS2012
Cristobal Navarro
Hay dos tipos de personas: las que te hacen perder el tiempo y las que te hacen perder la noción del tiempo
El secreto de la felicidad no está en hacer lo que te gusta, sino en que te guste lo que haces
User avatar
cnavarro
 
Posts: 6541
Joined: Wed Feb 15, 2012 8:25 pm
Location: España

Re: Drawing on a TImage and save

Postby Enrico Maria Giordano » Sun Mar 30, 2014 9:48 pm

Cristobal,

cnavarro wrote:This tested with VS2012


I'm using BCC581. Thank you anyway.

EMG
User avatar
Enrico Maria Giordano
 
Posts: 8710
Joined: Thu Oct 06, 2005 8:17 pm
Location: Roma - Italia

Re: Drawing on a TImage and save

Postby cnavarro » Sun Mar 30, 2014 9:50 pm

If you want to try it put an image is called word.jpg
Last edited by cnavarro on Sun Mar 30, 2014 11:14 pm, edited 1 time in total.
Cristobal Navarro
Hay dos tipos de personas: las que te hacen perder el tiempo y las que te hacen perder la noción del tiempo
El secreto de la felicidad no está en hacer lo que te gusta, sino en que te guste lo que haces
User avatar
cnavarro
 
Posts: 6541
Joined: Wed Feb 15, 2012 8:25 pm
Location: España

Re: Drawing on a TImage and save

Postby cnavarro » Sun Mar 30, 2014 9:53 pm

I'll try to compile with BCC582
Cristobal Navarro
Hay dos tipos de personas: las que te hacen perder el tiempo y las que te hacen perder la noción del tiempo
El secreto de la felicidad no está en hacer lo que te gusta, sino en que te guste lo que haces
User avatar
cnavarro
 
Posts: 6541
Joined: Wed Feb 15, 2012 8:25 pm
Location: España

Re: Drawing on a TImage and save

Postby Enrico Maria Giordano » Sun Mar 30, 2014 10:12 pm

Cristobal,

cnavarro wrote:https://www.dropbox.com/s/kwk4hd470beg5j8/IMAGEN.zip

If you want to try it put an image is called word.jpg


Thank you. Unfortunately, the image is out of alignment (ie. is slightly shifted).

EMG
User avatar
Enrico Maria Giordano
 
Posts: 8710
Joined: Thu Oct 06, 2005 8:17 pm
Location: Roma - Italia

Re: Drawing on a TImage and save

Postby Enrico Maria Giordano » Sun Mar 30, 2014 10:12 pm

Cristobal,

cnavarro wrote:I'll try to compile with BCC582


Thank you.

EMG
User avatar
Enrico Maria Giordano
 
Posts: 8710
Joined: Thu Oct 06, 2005 8:17 pm
Location: Roma - Italia

Re: Drawing on a TImage and save

Postby ukoenig » Mon Mar 31, 2014 12:06 pm

Enrico,
my first drawing-tests.

Do You want to paint freehand or lines ?
Maybe do You want also saving a RESIZED-result of the original ?

Drawing :
Image

Result of the saved image with a external image-editor :

Image

Best regards
Uwe :?:
Last edited by ukoenig on Tue Apr 01, 2014 9:11 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.
User avatar
ukoenig
 
Posts: 4043
Joined: Wed Dec 19, 2007 6:40 pm
Location: Germany

Re: Drawing on a TImage and save

Postby Enrico Maria Giordano » Mon Mar 31, 2014 12:11 pm

Uwe,

ukoenig wrote:Enrico,
my first tests.


Thank you.

ukoenig wrote:Do You want to paint freehand or lines ?


Lines. I'm doing some experiment too. I'd like to assign the new bitmap to the TImage control. It seems you have to play with hDCs (CreateCompatible...).

EMG
User avatar
Enrico Maria Giordano
 
Posts: 8710
Joined: Thu Oct 06, 2005 8:17 pm
Location: Roma - Italia

Re: Drawing on a TImage and save

Postby Enrico Maria Giordano » Mon Mar 31, 2014 12:48 pm

Solved!

Edit: not solved yet as drawing on the stretched image is not the same as drawing on the original one. :-(

Code: Select all  Expand view
#include "Fivewin.ch"


#define SRCCOPY 13369376


FUNCTION MAIN()

    LOCAL oDlg, oImg

    DEFINE DIALOG oDlg;
           SIZE 800, 600

    @ 0, 0 IMAGE oImg;
           FILE "SFONDO.JPG";
           ADJUST

    @ 15, 0 BUTTON "Draw";
            ACTION DRAWIMG( oImg )

    @ 15, 20 BUTTON "Save";
             ACTION oImg:SaveImage( "MYIMAGETEST.JPG", 2 )

    ACTIVATE DIALOG oDlg;
             CENTER

    RETURN NIL


STATIC FUNCTION DRAWIMG( oImg )

    LOCAL hDC := oImg:GetDC()

    LOCAL x, y

    FOR y = 10 TO 50
        FOR x = 10 TO 50
            SETPIXEL( hDC, x, y, CLR_HRED )
        NEXT
    NEXT

    UPDATEIMG( oImg, hDC )

    oImg:ReleaseDC()

    RETURN NIL


STATIC FUNCTION UPDATEIMG( oImg, hDC )

    LOCAL nWidth  := oImg:Super:Super:nWidth()
    LOCAL nHeight := oImg:Super:Super:nHeight()

    LOCAL hMemDC := CREATECOMPATIBLEDC( hDC )

    LOCAL hMemBmp := CREATECOMPATIBLEBITMAP( hDC, nWidth, nHeight )

    LOCAL hBmpOld := SELECTOBJECT( hMemDC, hMemBmp )

    LOCAL hBitmap  := oImg:hBitmap
    LOCAL hPalette := oImg:hPalette

    BITBLT( hMemDC, 0, 0, nWidth, nHeight, hDC, 0, 0, SRCCOPY )

    SELECTOBJECT( hMemDC, hBmpOld )

    DELETEDC( hMemDC )

    oImg:hBitmap = hMemBmp

    PALBMPFREE( hBitmap, hPalette )

    PALBMPNEW( oImg:hWnd, oImg:hBitmap, oImg:hPalette )

    RETURN NIL


EMG
User avatar
Enrico Maria Giordano
 
Posts: 8710
Joined: Thu Oct 06, 2005 8:17 pm
Location: Roma - Italia

Re: Drawing on a TImage and save [Solved]

Postby ukoenig » Mon Mar 31, 2014 1:39 pm

I added some options :

1. The dialog is adjusted to the image-size.

2. change LINESTYLE ( change from FREEHAND to LINES )
selecting lines : first click = startposition, second click = line-end.

3. change at runtime PEN-size and color

still have to add, moving a line

Image

Best regards
Uwe :lol:
Last edited by ukoenig on Mon Mar 31, 2014 6:07 pm, edited 9 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.
User avatar
ukoenig
 
Posts: 4043
Joined: Wed Dec 19, 2007 6:40 pm
Location: Germany

Re: Drawing on a TImage and save [Solved]

Postby Enrico Maria Giordano » Mon Mar 31, 2014 1:42 pm

Uwe,

you're a war-machine with your sample! :-)

EMG
User avatar
Enrico Maria Giordano
 
Posts: 8710
Joined: Thu Oct 06, 2005 8:17 pm
Location: Roma - Italia

Re: Drawing on a TImage and save [Solved]

Postby ukoenig » Mon Mar 31, 2014 6:06 pm

Enrico,

it is really fun, working with it.
do we still need to paint on a RESIZED image ?
added image-change and showing the used Pensize inside the combobox, You are drawing with.
A new selected image is adjusted inside the dialog with the new size.
Some more options will follow, like to define the EXPORT-image-name.

free painting on a image with different colors and pensizes
poor Olga :(

Image

The external Editor-preview of the saved result
We could do this from inside the program with a extra dialog.

Image

Added RESIZE and save to INI

Image

Added PREVIEW of the RESIZED EXPORT-image :
I think it is completed now ? or still something missing ?

Image

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.
User avatar
ukoenig
 
Posts: 4043
Joined: Wed Dec 19, 2007 6:40 pm
Location: Germany

Next

Return to FiveWin for Harbour/xHarbour

Who is online

Users browsing this forum: russimicro and 47 guests