Link to home
Start Free TrialLog in
Avatar of pigeonbr
pigeonbr

asked on

Resizing width and height of a jpg, resaving it in my VC++ 6.0 existing program

Hi all!
I have an ODBC database program for administering a client database, and when I change records the picture of the client is displayed in a picture box object. The user of the program has to manually resize the photos d/loaded from his digital camera every time he saves the jpg to the proper folder. What I would like is to modify the program to load the jpg original, resize it to the pixel dimensions I choose in the code to then load it into my picture box object which works fine. I don't want to redo the whole system of loading pictures to accomplish this...I want to use what I have and modify it to work.

I have found a class called CxImage that does do this (called Resample in menu) but it seems awfully complexe for m. I'm not an expert programmer and do this as a hobby and not for a living. Is there a simple way of using the Resample function in the CxImage class, or is there another way to do this with what I already have? In my project I have the CPicture2 class, CPicture, and CPicClip class. I only use the CPicture2 class so far. Can anybody lead me in the proper direction here please? Thanks! (I am trying to finish this in a week or so hopefully)

Avatar of AndyAinscow
AndyAinscow
Flag of Switzerland image

There are a number of links in this question which may be useful.

https://www.experts-exchange.com/questions/21480144/Resize-Images.html
Avatar of AlexFM
AlexFM

Instead of CxImage you can use GDI+ which has built-in support of JPEG format.

http://www.codeproject.com/vcpp/gdiplus/GdiPThumbnailsViewer.asp
Avatar of pigeonbr

ASKER

Thanks for your responses. I had a look at these links, some I already had....they are interesting. Let me be more specific in my thoughts: My program is using a CView which is main dialog screen. On it I have a Picture Box object in which I display a .jpg....works fine. I want to load the jpg as I'm doing now. I can resave it as a .bmp if this will help things using the SaveAsBitmap() in CPicture2 class...this works. If instead of using  CPaintDC, which I don't have because I'm using a CView class, how can I load the jpg I resaved as a bmp , resize IT if this is easier than resizing a jpg, and then display it either in my Picture Box object or otherwise ? Thanks!

This may be of use - once you have your picture in a CDC

CDC::StretchBlt
BOOL StretchBlt( int x, int y, int nWidth, int nHeight, CDC* pSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, DWORD dwRop );

Return Value

Nonzero if the bitmap is drawn; otherwise 0.

Parameters

x

Specifies the x-coordinate (in logical units) of the upper-left corner of the destination rectangle.

y

Specifies the y-coordinate (in logical units) of the upper-left corner of the destination rectangle.

nWidth

Specifies the width (in logical units) of the destination rectangle.

nHeight

Specifies the height (in logical units) of the destination rectangle.

pSrcDC

Specifies the source device context.

xSrc

Specifies the x-coordinate (in logical units) of the upper-left corner of the source rectangle.

ySrc

Specifies the x-coordinate (in logical units) of the upper-left corner of the source rectangle.

nSrcWidth

Specifies the width (in logical units) of the source rectangle.

nSrcHeight

Specifies the height (in logical units) of the source rectangle.

dwRop

Specifies the raster operation to be performed. Raster operation codes define how GDI combines colors in output operations that involve a current brush, a possible source bitmap, and a destination bitmap. This parameter may be one of the following values:

BLACKNESS   Turns all output black.


DSTINVERT   Inverts the destination bitmap.


MERGECOPY   Combines the pattern and the source bitmap using the Boolean AND operator.


MERGEPAINT   Combines the inverted source bitmap with the destination bitmap using the Boolean OR operator.


NOTSRCCOPY   Copies the inverted source bitmap to the destination.


NOTSRCERASE   Inverts the result of combining the destination and source bitmaps using the Boolean OR operator.


PATCOPY   Copies the pattern to the destination bitmap.


PATINVERT   Combines the destination bitmap with the pattern using the Boolean XOR operator.


PATPAINT   Combines the inverted source bitmap with the pattern using the Boolean OR operator. Combines the result of this operation with the destination bitmap using the Boolean OR operator.


SRCAND   Combines pixels of the destination and source bitmaps using the Boolean AND operator.


SRCCOPY   Copies the source bitmap to the destination bitmap.


SRCERASE   Inverts the destination bitmap and combines the result with the source bitmap using the Boolean AND operator.


SRCINVERT   Combines pixels of the destination and source bitmaps using the Boolean XOR operator.


SRCPAINT   Combines pixels of the destination and source bitmaps using the Boolean OR operator.


WHITENESS   Turns all output white.
Remarks

Copies a bitmap from a source rectangle into a destination rectangle, stretching or compressing the bitmap if necessary to fit the dimensions of the destination rectangle. The function uses the stretching mode of the destination device context (set by SetStretchBltMode) to determine how to stretch or compress the bitmap.

The StretchBlt function moves the bitmap from the source device given by pSrcDC to the destination device represented by the device-context object whose member function is being called. The xSrc, ySrc, nSrcWidth, and nSrcHeight parameters define the upper-left corner and dimensions of the source rectangle. The x, y, nWidth, and nHeight parameters give the upper-left corner and dimensions of the destination rectangle. The raster operation specified by dwRop defines how the source bitmap and the bits already on the destination device are combined.

The StretchBlt function creates a mirror image of a bitmap if the signs of the nSrcWidth and nWidth or nSrcHeight and nHeight parameters differ. If nSrcWidth and nWidth have different signs, the function creates a mirror image of the bitmap along the x-axis. If nSrcHeight and nHeight have different signs, the function creates a mirror image of the bitmap along the y-axis.

The StretchBlt function stretches or compresses the source bitmap in memory and then copies the result to the destination. If a pattern is to be merged with the result, it is not merged until the stretched source bitmap is copied to the destination. If a brush is used, it is the selected brush in the destination device context. The destination coordinates are transformed according to the destination device context; the source coordinates are transformed according to the source device context.

If the destination, source, and pattern bitmaps do not have the same color format, StretchBlt converts the source and pattern bitmaps to match the destination bitmaps. The foreground and background colors of the destination device context are used in the conversion.

If StretchBlt must convert a monochrome bitmap to color, it sets white bits (1) to the background color and black bits (0) to the foreground color. To convert color to monochrome, it sets pixels that match the background color to white (1) and sets all other pixels to black (0). The foreground and background colors of the device context with color are used.

Not all devices support the StretchBlt function. To determine whether a device supports StretchBlt, call the GetDeviceCaps member function with the RASTERCAPS index and check the return value for the RC_STRETCHBLT flag.

CDC Overview |  Class Members |  Hierarchy Chart

See Also   CDC::BitBlt, CDC::GetDeviceCaps, CDC::SetStretchBltMode,::StretchBlt

Hi AndyAinscow,
I was aware of the StretchBlt() function from a book I have...I could see using this function, the thing I am not clear on is how do I get from the CDC to my Picture Box...here is my current code for loading the jpg:

            CString strFrontString ="c:\\photos\\";
            CString strWholeString = (strFrontString + strNoClient+".jpg");
            
                  if(m_cpicCustomer.Load(strWholeString))
                  {
                        HRESULT hr = m_cpicCustomer.m_IPicture2->get_Handle((OLE_HANDLE*)    &m_hbmpCustomer);
                        m_ctlPicBmp.SetBitmap(m_hbmpCustomer);
                        
                  }
Can you point me in the right direction please ? Thanks!

I'll think about it and get back tomorrow.
Hi AndyAinscow,
Just found something I will look into...have a look at it...I will try to understand the code...if you have foundsomething as well, please let me know...here is the code I found on getting a DC on a Picturebox:
Hi,

I try  to get a device-context on a picturebox to draw a
graph in it in my FormView-Project!

Thats the way, I tried it:

void CPowerCheckView::OnDraw(CDC* pDC)
{    
CWnd *pWnd = GetDlgItem(IDC_PLACE);
CDC *hdc = pWnd->GetDC();    

static int i;
hdc->Rectangle(1+i, 1+i, 100, 100);
//hdc->ReleaseOutputDC(hdc);        
i +=10;
}

That works, but I got two problems with it:
1. if the rectangle is redrawn, the old one is still existing, so I got a rectangle for every redraw!! I just
want one!
2. On resizing it disapears, how can i manipulate the
WM_SIZE?

Thank you for your tip!

ciao
gonzales
*************************************
I will study and see if I can adapt it. I await your thoughts Andy, Thanks!
SOLUTION
Avatar of hemakumar
hemakumar

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
A little theory.
Drawing in windows is a two step process, typically invoked by an Invalidate() (or related function) call.  Resizing will call invalidate.
First the WM_ERASEBKGRND message is generated.  Typically the window is then filled with the default colour.  (Everything is erased).
Then the WM_PAINT message which will result in your OnDraw being called.  (Incidentally this is the major cause of flickering)

If the rectangle remains it sounds like either you are calling OnDraw directly or the background erasing is not being performed.  For it to work properly with a resize it makes me think you are calling OnDraw directly.  If that is the case then just try Invalidate()
Ok...I had some time to try the code I have put forward by gonzales on a previous question...After applying the Invalidate() as youo both pointed out, and releaseing the DC, and adjusting my rectanglre size, I get a rectangle. Ok...but I think we are getting sidetracked by this code I found. How do I actually load jpg (or bmp) into the rectangle? And will the jpg be resized automatically to the size of the rectangle?
If you can get the jpg to a bitmap then you can use the StretchBlt to display it at a different size.  Once you have it as a bitmap then it 'should' be easy going.
Ok..lets recap..

I have succeeded in loading my jpg, and resaving it as a bmp. Great. Now, correct me if my thinking is wrong...the next step would be to load the bmp, and resize it.
Next, would be to display it.

So, to load the bmp, I have tried the following...keep into consideration I am using CView class with a picture box object up till now. Here is my code:
      //Step 1*************
      //Code to load photo at startup to be able to create the bmp.
      CString strNoClient = m_pSet->m_No_client;
      if(strNoClient =="")
      {
            m_cpicCustomer.Load("c:\\photos\\0000.jpg");
            //after calling this Load, the bmp has been created and saved as
            //("c:\\photos\\Current.bmp").The bmp is created in CPicture2 class called when
            //Load() is called here.
            
      }

      //Step 2******************
      //load the bmp and resize it. This I'm not sure of...this is code from a book I have and they use a CPaintDC, which is not what I want to use....I need to ( I imagine) use a memdc only...what should i modify??
      
      CPaintDC dc(this);
      HBITMAP hbitmap;
      hbitmap = ::LoadBitmap(m_hInstance,"c:\\photos\\current.bmp");//name of my bmp to load

      //Create a new memory DC
      HDC hMemDC = ::CreateCompatibleDC(NULL);
      SelectObject(hMemDC,hbitmap);
      //Copy the memory dc into the screen dc
      ::StretchBlt(dc.m_hDC,      //destination
            0,
            0,
            128,//desired width in pixels
            144,//desired height in pixels
            hMemDC,      //Source
            0,
            0,
            250,      //what if every bmp is not the same size? What do I put here?
            250,
            SRCCOPY);

      //Delete the memory DC and the bitmap
      ::DeleteDC(hMemDC);
      ::DeleteObject(hbitmap);      

So, what do I need to modify to get the bmp into the correct dc for StretchBlt to work? This is what is not clear. Also, when it does get into the dc properly, how do I transfer it to the picture box object for display?
Her is the code we were talking about earlier with respect to creating the rectangle to display in...
      //Step 3***
      //
      //create rectangle
      CWnd *pWnd = GetDlgItem(IDST_PicBmp);
      pWnd->Invalidate();//repaints picture box and erases old one.
      CDC *hdc = pWnd->GetDC();
      static int i;
      hdc->Rectangle(i,i,128,144);
      pWnd->ReleaseDC(hdc);
...this gets a handle on the picture box , but how do I actually point it to the bmp?? Hope you can help me see the light :)

1)//what if every bmp is not the same size? What do I put here?
to get the exact size of bmp as it varies.
soln2:
  HBITMAP hbitmap;
     hbitmap = ::LoadBitmap(m_hInstance,"c:\\photos\\current.bmp");//name of my bmp to load
CBitmap bitmap;
 bitmap.Attach(hbmp);
      BITMAP bm;
      bitmap.GetObject(sizeof(BITMAP),&bm);
  now bm gets the exact width and height of the bitmap which u can use in StretchBlt

2)How to draw bitmap in picturebox.

   CWnd *pWnd = GetDlgItem(IDST_PicBmp);
     pWnd->Invalidate();//repaints picture box and erases old one.
     CDC *hdc = pWnd->GetDC();
      CDC memdc;//used for buffering which inturn provides performance
        memdc.CreateCompatibleDC(hdc);//memdc should be compatible to picturebox dc.

    now use hdc->StrechBlt(.,.,,,);

the first two signfies dest.co-ordinates,third and fourth dest.width and height.fifth memdc.6th& 7th
source coordinates,8&9 source width and height bm.bmWidth and bm.bmHeight and last is SRCCOPY.

any problems getback

BOOL StretchBlt (
int x,
int y,
int nWidth,
int nHeight,
CDC* pSrcDC,
int xSrc,
int ySrc,
int nSrcWidth,
int nSrcHeight,
DWORD dwRop );







Once you have the bitmap in a DC then you can paint it directly to the dialog - no picture box required.
Hi guys,
OK...looks like I'm getting very close...thanks to both of you...there is no compiling errors, but program crashes at this line:
              bitmap.GetObject(sizeof(BITMAP),&bm);

I corrected a typo (bitmap.Attach(hbmp)  is now bitmap.Attach(hbitmap)

Here is all my code so far..:
      //Step 1
      //Code to load photo at startup to be able to create the bmp.
      CString strNoClient = m_pSet->m_No_client;
      if(strNoClient =="")
      {
            m_cpicCustomer.Load("c:\\photos\\0000.jpg");
            //after calling this Load, the bmp has been created and saved as
            //("c:\\photos\\Current.bmp").The bmp is created in CPicture2 class called when
            //Load() is called here.
            
      }

      //Step 2
      //load the bmp and get size info.      
      HBITMAP hbitmap;
             hbitmap = ::LoadBitmap(m_hInstance,"c:\\photos\\current.bmp");//name of my bmp to load
      CBitmap bitmap;
       bitmap.Attach(hbitmap);
              BITMAP bm;
              bitmap.GetObject(sizeof(BITMAP),&bm);
        //now bm gets the exact width and height of the bitmap which u can use in StretchBlt

      //Step 3
      //Drawing picture in Picture Box
      CWnd *pWnd = GetDlgItem(IDST_PicBmp);
     pWnd->Invalidate();//repaints picture box and erases old one.
     CDC *hdc = pWnd->GetDC();
      CDC memdc;//used for buffering which inturn provides performance
        memdc.CreateCompatibleDC(hdc);//memdc should be compatible to picturebox dc.

      //Step 4
      //**Resize and display picture
      //Copy the memory dc into the screen dc
      hdc->StretchBlt(0,//destination coordinates
            0,
            128,//desired width in pixels
            144,//desired height in pixels
            hdc,      //Source
            0,
            0,
            bm.bmWidth,      //Width of original image
            bm.bmHeight,      //Height of original image
            SRCCOPY);
      //the first two signify dest. co-ordinates, third & forth dest.width and height,
      //fifth memdc,6th & 7th source coordinates, 8th & 9th source width and
      //height (bm.bmWidth and bm.bmHeight and last is SRCCOPY.

      //Delete the memory DC and the bitmap
      ::DeleteDC(memdc);
      ::DeleteObject(hbitmap);      

I can't figure out why the program crashes at the line indicated above...any ideas hemakumar?Thanks.
Good day guys,

I await your thoughts on my last comment: Why the line
bitmap.GetObject(sizeof(BITMAP),&bm);

causes a crash....the sizeof() is ok, but the problem is either the &bm or with the GetObject call....can't figure out what is making the crash. Thanks.
Did u check whether the  LoadBitmap is successful?

Once ur job is over at the end of the function call

bitmap.Detach();//mandatory.
check it and getback.
      hbitmap = ::LoadBitmap(m_hInstance,"c:\\photos\\current.bmp");//name of my bmp to load
is hbitmap non zero ?  (zero would be a failure to load)


int iRet = bitmap.Attach(hbitmap);
is iRet non zero? (again zero is failure)
Hi Guys,

Ok...you were both right....the bmp is not properly loaded...here is my code so far:

      //Step 2
      //load the bmp and get size info.
      HINSTANCE m_hInstance;
      HBITMAP hbitmap;
      hbitmap = ::LoadBitmap(m_hInstance,"c:\\photos\\current.bmp");//name of my bmp to load
      CBitmap bitmap;
       bitmap.Attach(hbitmap);
              BITMAP bm;
              bitmap.GetObject(sizeof(BITMAP),&bm);
        //now bm gets the exact width and height of the bitmap which u can use in StretchBlt
      bitmap.Detach();      //releases bitmap every time you use LoadBitmap()

The bmp is in the correct directory. Is the HINSTANCE the problem? Am I not declaring it properly?

I've also started working on another way...using about the same procedure in OnDraw() in the CView to accomplish the same thing. When I get it working the way we are doing here, I might opt to put the code in the OnDraw.

Ok...I'm not up to speed on all the theory on alot of things...correct me if I'm wrong, but I think my problem is to do with the HINSTANCE m_hInstance variable...I just realized it's not connected properly I think...can one of you clear me up on this poit please? m_hInstance has to be a member of the class I'm using it in...it's not a member of the CBitmap class, so what how exaclty should I use it here? Thanks.
Hi,
Did some searching....looks like the m_hInstance variable has to be a handle on the window I'm working in. In my case, I'm working in a CView class, and the m_hInstance is not available thru that class....so what do I get a handle to with the m_hInstance for use in the LoadBitmap() ??

I think life will be easier if we forget about the original picture box object. Using the StretchBlt() I will be able to place the picture easily to left top corner of the CView dialog I'm using.

I'm getting closer.Thanks....I continue to try stuff while awaiting your response.
Hi,
To my CView class, I added HINSTANCE m_hInstance to the constructor.

Then, I created InitInstance() and added
CMyView myView;
myView.m_hInstance = m_hInstance;

When I run my app, I still get a crash at the same place:
      HBITMAP hbitmap;
      CBitmap bitmap;
      hbitmap = ::LoadBitmap(m_hInstance,"c:\\photos\\current.bmp");//name of my bmp to load
       bitmap.Attach(hbitmap);
              BITMAP bm;
              bitmap.GetObject(sizeof(BITMAP),&bm);

..because the hbitmap = 0...why is it not loading ?
Something is fishy with my m_hInstance....I've tried several things....no change...I await your return :) Thanks.
Hi its me again.... I got it working in OnDraw() in my CView class.....here is the code:

void CFormomaxView::OnDraw(CDC *pDC)
{
 HBITMAP m_hBitmap;
 CBitmap bitmap;
 BITMAP bm;
      m_hBitmap=(HBITMAP)::LoadImage(
      NULL,"c:\\photos\\current.bmp",IMAGE_BITMAP,
      0,0,LR_LOADFROMFILE|LR_DEFAULTSIZE);
        int iRet=bitmap.Attach(m_hBitmap);//load failed if iRet=0.

        bitmap.GetObject(sizeof(BITMAP),&bm);
      CBitmap *mbmp=CBitmap::FromHandle(m_hBitmap);
      CDC *memDC=new CDC;
      memDC->CreateCompatibleDC(pDC);
      memDC->SelectObject(mbmp);
         pDC->StretchBlt(10,10,128,144,memDC,0,0,bm.bmWidth,bm.bmHeight,SRCCOPY);
      delete memDC;


}

//*********************

Now I will adapt it to my program. Thanks both of you for your help and inspiration! I will split the points in two if it is ok with both of you. I await your feedback if this is satisfactory to you both.
If you think both of us helped then a split is appropriate.


I wasn't working during your last series of posts.  This is for completeness.

AfxGetInstanceHandle  
HINSTANCE AfxGetInstanceHandle( );

Return Value

An HINSTANCE to the current instance of the application. If called from within a DLL linked with the USRDLL version of MFC, an HINSTANCE to the DLL is returned.

Go ahead.
Thanks alot again guys ...really appreciate it!