Solved

Printing a high resolution image

Posted on 2000-05-14
27
686 Views
Last Modified: 2013-11-20
Hi ! I have problem in printing high resolution images.
I'm trying to print a A4 Size 300dpi bitmap image to some different colour printers. However, I never print anything out succesfully. (The printer does not printout anything at all). The printers I used are SONY UDP-8800 (a professional photo printer with 30mb RAM on board), HP PhotoSmart (an ink-jet printer with NO on board memory).
If I lower the original image resolution to say 100dpi, then I can printout the image successfully. Or if I make the size of the original image smaller and then enlarge it to A4 output size.. then it's ok too..
However, if I use photoshop to print the original high resolution A4 image, I can print it out properly....
Can anyone tell me why is it and how to solve it?

I'm using the following code in my printing function to load and print the image:


.
.
.
CString m_sBitmap="c:\\hires.bmp";
CBitmap m_bmpBitMap;
HBITMAP hbitmap=(HBITMAP)::LoadImage(AfxGetInstanceHandle(),m_sBitmap,IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION);
if(hbitmap)
{
      if(m_bmpBitMap.DeleteObject())
            m_bmpBitMap.Detach();
      m_bmpBitMap.Attach(hbitmap);
}
BITMAP bm;
m_bmpBitMap.GetBitmap(&bm);
CDC dcMem;
dcMem.CreateCompatibleDC(&dcPrinter);
CBitmap *pOldBitmap=(CBitmap*)dcMem.SelectObject(m_bmpBitMap);
dcPrinter.StretchBlt(0,0,pageWidth,pageHeight,&dcMem,0,0,bm.bmWidth,bm.bmHeight,SRCCOPY);

My friend has written another Borland C Builder application to do the same job and he got the same problem.
0
Comment
Question by:rw8
  • 16
  • 10
27 Comments
 

Author Comment

by:rw8
ID: 2809318
I tried to print the hi resolution image using the following applications but none of them can print it out successfully: Microsoft Word (office 95), ACDSee Ver 3.0 Trial..etc

0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 2809444
Do you know if the load of the imageinto your m_bmpBitMap worked ok?

If so, try printing to the printer in bands (ie. don't StretchBlt the whole thing in oe go, but do strips instead)

If not, then windows is simply not able to find a big enough lump of contiguous memory, or there is some internal limit to LoadImage.  Try using the OleLoadPicture API instead.  This has the advantage of also being able to directly load JPG and GIF images.

0
 

Author Comment

by:rw8
ID: 2812735
it seems I can load the image successfully..  since I also tried to use some other methods to load the image and then save it to some other files and I can get the output file succesfully.,. btw,  how to print it in bands? I tried to use the function ExtEscape to do banding... but I always got a return value of 0 when calling this function... got any idea about it?
0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 2812816
Just make multiple class to StretchBlt.

eg. instead of
dcPrinter.StretchBlt(
  0,0,pageWidth,pageHeight,
  &dcMem,
  0,0,bm.bmWidth,bm.bmHeight,
  SRCCOPY);

try something like this...

int pageBandHeight = pageHeight/4;
int bmBandHeight = bm.bmHeight/4;
for (i = 0; i < 4; i++) {
  dcPrinter.StretchBlt(
    0,i*pageBandHeight,
    pageWidth,pageBandHeight,
    &dcMem,
    0,i*bmBandHeight,
    bm.bmWidth,bmBandHeight,
    SRCCOPY);
}

NOTE: this assumes the hieght are evenly divisible by 4, but you should get the idea.


0
 

Author Comment

by:rw8
ID: 2812959
no sorri.. still doesn't work..
I tried use CDC::Escape() to do banding but it does not help since my printers (hardware) does not support banding.. (i.e. banding= no banding)
0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 2813158
Don't use the Escape function.  And try more bands .. maybe 4 is not enough.
0
 

Author Comment

by:rw8
ID: 2813270
it seems to me that no matter how many pieces I divide the image into... if the total size exceeds 16Mb.. then it doesn't work...
btw, the printer I'm using are a bit old .. (I think they are 3-4 yrs old).. is it possible that the driver does not support printing that large image?
Since if I use some custom image processing library to print to the printer directly.. (bypass the printer driver).. then I can printout the image.. however, the quality is very bad..
0
 

Author Comment

by:rw8
ID: 2856692
Does not work. It seems that the problem comes from the printer driver. I tried to use some newer colour printers and it is ok.
0
 

Expert Comment

by:MrDaveB
ID: 2858684
Hi,

I've had the same problem before. The problem is that the StretchBlt function does not work on very large images. This is only a problem for 95 and 98. In the end I had to print my image in bands. This involved multiple calls to the StretchBlt function.

Here is what MSDN says on the issue:

BUG: StretchBlt()/StretchDIBits() Fail with Very Large Stretch
ID: Q111865

 
3.00 3.10 WINDOWS kbprg kbbuglist
--------------------------------------------------------------------------------
The information in this article applies to:

Microsoft Windows Software Development Kit (SDK) for Windows versions 3.0 and 3.1

--------------------------------------------------------------------------------


SYMPTOMS
If the stretching factor is large, for example, when stretching from a very small to a large height, StretchDIBits() and StretchBlt() may return zero (0) and display nothing. The same bitmap with a smaller stretch is displayed correctly.



CAUSE
Most display drivers do not implement their own StretchBlt() or StretchDIBits() so GDI must simulate these calls. Part of the GDI simulation involves allocating temporary work buffers, which are limited to 64K. If the size of the work buffer is calculated to be greater than 64K, then the height of the source and destination rectangles are halved until they are less than 64K. The problem is that if GDI must continue to divide the height by two (2) to get a buffer less than 64K, the source or destination height could eventually reach one scan line. At this point, the call fails because it cannot break up a scan line into subunits.

StretchBlt() and StretchDIBits() are not designed to provide unlimited stretching. However, they may fail a bit more prematurely than their design limitation.



RESOLUTION
If StretchBlt() or StretchDIBits() fails on a large stretch, an application can divide up the source bitmap, stretch the pieces individually, and position them correctly once stretched. Another alternative is to do a smaller stretch. There is no formula to determine exactly what bitmaps will fail at what stretch size.



STATUS
Microsoft has confirmed this to be a bug in the Microsoft products listed at the beginning of this article.



MORE INFORMATION
To reproduce the problem, create a bitmap approximately 2048 pixels wide by 16 pixels high. Then, display the bitmap with the DIBVIEW sample from the Windows 3.1 SDK. Choose Stretch To Window from DIBVIEW's Options menu, so that the bitmap is stretched according to the size of the client window. When the height is more than about 200 pixels, the bitmap will not be displayed.

Additional query words: buglist3.00 buglist3.10 3.00 3.10 fail zoom


Keywords          : kbWinOS310 kbDSupport kbWinOS300 kbSDKWin16
Version           :
Platform          :
Issue type        : kbbug
 


Last Reviewed: July 14, 1999
© 1999 Microsoft Corporation. All rights reserved. Terms of Use.
 



--------------------------------------------------------------------------------
Send feedback to MSDN.Look here for MSDN Online resources
0
 

Author Comment

by:rw8
ID: 2859926
But why is that I have no problem in printing those big images when I use some late model printers? (e.g. Epson PhotoStylus 700)

0
 

Author Comment

by:rw8
ID: 2860115
Mr DaveB, can you also tell me how you print your image in bands? I tried using "ExtEscape" to do banding but it does not help me.
0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 2860219
I have alreaduy suggested printing in bands and rw8 says that this doesn't help him.

That should not be proposed as an answer, because a) it is exactly the same what I already proposed and b) it doesn't explain the problem as it appears to be printer specific.

The problem could be the page size that is being blt'd to.  Did you get teh size from the printer deveice capabilities?
0
 

Author Comment

by:rw8
ID: 2860264
Yes. I can get the print page size. (and remember that I cannot printout those high resolution images using some other commerical software as well)
I cannot verify what MrDaveB said is correct or not (he said the problem is due to the limitation of win95/98) since I can't find any WINNT drivers for the printers I'm using (that cannot print out the high resolution images).
0
What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 10

Expert Comment

by:RONSLOW
ID: 2860322
Eh ??? .. this is the opposite of what you said initially

"However, if I use photoshop to print the original high resolution A4 image, I can print it out properly....
Can anyone tell me why is it and how to solve it?

Please verify: Can you print successfully with all / some / no other (commercial) software?

BTW: Does your StretchBlt function return an OK status ?
0
 

Author Comment

by:rw8
ID: 2860412
sorry that I didn't explain very clearly.. I CAN print out the high resolution A4 image using Photoshop. (but only photoshop).. then I tried to print the same image using other commercial software (like ACDsee  and MS Word) and it didn't work.

I'll tell you the return value of "StretchBlt" tomorrow since I have deleted my project (by mistake) and I'm trying to rebuild the project from my backup files right now :(
0
 

Author Comment

by:rw8
ID: 2866244
I found that I have problem in loading big BMP images. I tried to load a bitmap image with resolution around 3000*2000 pixels (24 bit colour) .. and it seems that the image cannot be loaded at all.. (therefore can't verify whether the stretchBlt function works or not) and then when I decrease the image to a much smaller size .. then it's ok.. (and the stretchBlt function returns ok.
Anyway, I copied my sample code which I'm using to test printing images... maybe you guys can copy it and see what's wrong :P


void CBandingDlg::OnButton1()
{

      CPrintDialog dlg(FALSE);
      if(dlg.DoModal()==IDOK)
      {
            
      
            HDC hdcPrinter = dlg.CreatePrinterDC();
            if (hdcPrinter == NULL)
            {
                  MessageBox(_T("Sorry. You don't have a printer!"));
                  return;
            }
            else
            {
                  CDC dcPrinter;
                  dcPrinter.Attach(hdcPrinter);
                  DOCINFO docinfo;
                  memset(&docinfo, 0, sizeof(docinfo));
                  docinfo.cbSize = sizeof(docinfo);
                  docinfo.lpszDocName = _T("Banding");
                  
                  
                  HIGEAR hiResImage,hi1,hi2;                  
                  StartDoc(hdcPrinter,&docinfo);
                  StartPage(hdcPrinter);

                                                      
      
                  BOOL bError=FALSE;
                  RECT rect;
                  int xPage,yPage;
                  xPage=GetDeviceCaps(hdcPrinter,HORZRES);
                  yPage=GetDeviceCaps(hdcPrinter,VERTRES);

                  CString m_sBitmap="c:\\hires.bmp";
            CBitmap m_bmpBitMap;
            HBITMAP hbitmap=(HBITMAP)::LoadImage(AfxGetInstanceHandle(),m_sBitmap,IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION);

            if(hbitmap)
            {
                        if(m_bmpBitMap.DeleteObject())
                              m_bmpBitMap.Detach();
                m_bmpBitMap.Attach(hbitmap);
            }
            BITMAP bm;
            m_bmpBitMap.GetBitmap(&bm);
            CDC dcMem;
            dcMem.CreateCompatibleDC(&dcPrinter);
            CBitmap *pOldBitmap=(CBitmap*)dcMem.SelectObject(m_bmpBitMap);


                  int pageBandHeight = yPage/4;
            int bmBandHeight = bm.bmHeight/4;
                  int i;
            for (i = 0; i < 4; i++)
                  {
                        dcPrinter.StretchBlt(
                        0,i*pageBandHeight,
                        xPage,pageBandHeight,
                        &dcMem,
                0,i*bmBandHeight,
                bm.bmWidth,bmBandHeight,SRCCOPY);
            }

                  EndPage(hdcPrinter);
                  EndDoc(hdcPrinter);
                  DeleteDC(hdcPrinter);

            }
            return;
      }
}
0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 2866394
So does this mean you don't know whether or not the printing works, because you cannot load in an image big enough to print.

In that case, the code above isn't going to tell us much.  It is quite likely that the printing is working ok .. just that there is nothing to print.

Is that indeed the case?

NOTE: There are limits to the size of bitmap that can be read .. you need  conigutous memory for a bitmap, and 3000x2000x24bit = 18,000,000 bytes ~= 18MB.  That's a lot of contiguous memory to find.

Have you tried checking the success of LoadImage.  If it fails, call GetLastError to find out why.


0
 

Author Comment

by:rw8
ID: 2871654
Since I found that the value o hbitmap is 0x000000 after LoadImage.. so I added a line
DWORD a=GetLastError() immediately after the line:
HBITMAP
                   hbitmap=(HBITMAP)::LoadImage(AfxGetInstanceHandle(),m_sBitmap,IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION);

and a is equal is 0 ..  (which means LoadImage was successful??)


One more thing is that I was not using LoadImage, StretchBlt..etc to load and print the image at first.. I was using an image library from Accusoft to do these jobs. and I'm sure the image was loaded successfully. And when I use Accusoft to print it out.. I cannot get the printout as well.. however, there is an option in accusoft's print function so that I can choose to NOT use the printer's driver and ask accusoft to deal with the printing process itself... in this case, I can printout the high resolution image.. BUT the image quality is very very poor..

0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 2872316
Are you using Win95/98 ?  If so, you won't get error codes because Win95/98 doesn't support GetlastError for most GDI (and other) functions.

I imagine that the Accusoft printing is adjusting the resolution so that it fits.

Also, it would be interesting to try using OleLoadPicture instead of LoadImage, as this may work correctly.

Have you tried using another printer driver for that same brand (but maybe for a less capable model).  That might help.
0
 

Author Comment

by:rw8
ID: 2872404
1. Yes. I'm using Win95/98 to get the error msg. Actually I have tried to use WinNT to load the image and it was loaded successfully. however, the printers I'm using do not have any NT driver at all, so I cannot test the printing under NT.


2.This is what the Accusoft help file says about it's print function:
IG_print_image ( HIGEAR hIGear, BOOL bDirectToDriver );

This function prints a HIGEAR image to the current default printer (or prints only its image rectangle, if you have called IG_image_rect_set()for this image).  Argument bDirectToDriver, when TRUE, instructs ImageGear to send the image’s DIB directly to the printer’s device driver.  In this case the entire procedure has been placed in the hands of the driver.  If your printer has special capabilities such as color, and if the driver supports these, then your image can be printed with these features.
 
So if I set bDirectToDriver=false.. then it can print.


3. I did try to use OleLoadPicture to load the image.. but since my programming skill is limited.. I can't figure out how to call this function :P
0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 2872414
It's not TOO tricky once you manage to get a stream that corresponds to your file.
0
 

Author Comment

by:rw8
ID: 2877758
Sorry.. I'm a bit dumb.. can't make it work.. (I haven't do any OLE programming b4)
is it easy for u to show me how to use it?
0
 
LVL 10

Accepted Solution

by:
RONSLOW earned 100 total points
ID: 2878684
Have you looked at the LoadPic sample yet?

What I did to make it easier was enhance CPictureHolder so I could more easily get at the handles, copy them around and load from file.  ONce loaded, I can Render it directly onto a DC, or get at the HBITMAP handle and do other bitmap-like things with it.

Here is my (cut down and simplified to what you should need) code...

#define RELEASE(lpUnk) do { if ((lpUnk) != NULL) { (lpUnk)->Release(); (lpUnk) = NULL; } } while (0)

class CMyPictureHolder : public CPictureHolder {
public:
    CMyPictureHolder() {}
    CMyPictureHolder(const CMyPictureHolder& holder) {
        m_pPict = holder.m_pPict;
        if (m_pPict) m_pPict->AddRef();
    }
    bool HasPicture() const { return m_pPict; }
    OLE_HANDLE GetHandle() {
        OLE_HANDLE handle = NULL;
        if (m_pPict != NULL) {
            m_pPict->get_Handle(&handle);
        }
        return handle;
    }
    operator HBITMAP() {
        if (GetType() == PICTYPE_BITMAP) {
            return (HBITMAP)GetHandle();
        } else {
            ASSERT(false);
            return NULL;
        }
    }
    CMyPictureHolder& operator=(const CMyPictureHolder& from) {
        if (this != &from) {
            IPicture* pPict = m_pPict;
            m_pPict = from.m_pPict;
            if (m_pPict) m_pPict->AddRef();
            RELEASE(pPict);
        }
        return *this;
    }
    bool OleLoadPictureFromFile(LPCTSTR lpszName) {
        CFile file;
        if (file.Open(lpszName,CFile::modeRead|CFile::typeBinary)) {
            return OleLoadPictureFromCFile(file);
        }
        return false;
    }
    bool OleLoadPictureFromCFile(CFile& file) {
        DWORD dwSize = file.GetLength();
        if (-1 == dwSize) return false;
        // alloc memory based on file size
        HGLOBAL hGlobal = ::GlobalAlloc(GMEM_MOVEABLE, dwSize);
        ASSERT(NULL != hGlobal);
        if (NULL == hGlobal) return false;
        LPVOID pvData = ::GlobalLock(hGlobal);
        ASSERT(NULL != pvData);
        if (NULL == pvData) return false;
        // read file and store in global memory
        DWORD dwBytesRead = file.ReadHuge(pvData,dwSize);
        ASSERT(dwBytesRead == dwSize);
        if (! dwBytesRead) return false;
        // finished with handle for now ..
        // but keep the block to read from for OleLoadPicture below
        ::GlobalUnlock(hGlobal);
        bool ok = OleLoadPictureFromGlobal(hGlobal);
        ::GlobalFree(hGlobal);
        return ok;
    }
    bool OleLoadPictureFromGlobal(HGLOBAL hGlobal) {
        if (! hGlobal) return false;
        // create IStream* from global memory
        // (the TRUE means deleted on release)
        LPSTREAM lpStream = NULL;
        {
            HRESULT hr = ::CreateStreamOnHGlobal(hGlobal, FALSE, &lpStream);
            ASSERT(SUCCEEDED(hr) && lpStream);
            if (! SUCCEEDED(hr) || ! lpStream) return false;
        }
        bool ok = OleLoadPictureFromStream(lpStream);
        RELEASE(lpStream);
        return ok;
    }
    bool OleLoadPictureFromStream(LPSTREAM lpStream) {
        if (! lpStream) return false;
        HRESULT hr = ::OleLoadPicture(lpStream, 0, FALSE, IID_IPicture, (LPVOID*)&m_pPict);
        return SUCCEEDED(hr);
    }
};

NOTE: This also handles metafiles (but you may need a little of the code I chopped out).
0
 

Author Comment

by:rw8
ID: 2894032
Band printing doesn't help and RONSLOW did suggested this to me already
0
 

Author Comment

by:rw8
ID: 2894091
Comment accepted as answer
0
 

Author Comment

by:rw8
ID: 2894092
Thanx Ronslow. I found the problem really comes from the printer driver. After I obtained the latest version printer driver from the manufacturer, it solved the problem automatically.
0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 2894888
That's good .. couldn't think of anything else to explain it :-)
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Introduction: Load and Save to file, Document-View interaction inside the SDI. Continuing from the second article about sudoku.   Open the project in visual studio. From the class view select CSudokuDoc and double click to open the header …
Introduction: Finishing the grid – keyboard support for arrow keys to manoeuvre, entering the numbers.  The PreTranslateMessage function is to be used to intercept and respond to keyboard events. Continuing from the fourth article about sudoku. …
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
This tutorial demonstrates a quick way of adding group price to multiple Magento products.

705 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now