Controlling Progressive Loads and Saves

The LEAD and JPEG (JFIF) file formats can be extended to support progressive loading and saving of images. Progressive loading is useful for transmitting images, because the first part of the file contains the full dimensions of the image. Therefore, in a paint-while-load routine, you can display the whole image, then progressively clarify it as the rest of the file loads.

Since the progressive formats are newer, some existing applications do not support them. Therefore, especially when saving a file that may be read by another application, you must pay attention to the Passes field in the SAVEFILEOPTION structure.

All of the class library save functions take a pSAVEFILEOPTION argument, which defaults to NULL.

When NULL is passed for this argument, the Passes field of the SAVEFILEOPTION structure defaults to 0, which means the file saved will not be progressive. Alternatively, you can do the following:

 

SAVEFILEOPTION SaveOption;

 

LBaseFile::GetDefaultSaveFileOption(&SaveOption);

 

//Set any of the SaveOption fields

 

//pass &SaveOption to any of the Save member functions

Since the default for Passes=0, the saved file will not be progressive.

Technically, only files with more than three passes are progressive files. They include full color in the low-resolution first pass; subsequent passes improve the resolution. Files that contain two or three passes are multiscan files. They include grayscale information in the first pass, and color information in the subsequent pass or passes.

If you want to save a progressive file or take advantage of this feature when loading a progressive file, you can control the number of passes that are required to complete the image. For more information, refer to the Passes field in the SAVEFILEOPTION structure.

JBIG also supports progressive loading of an image. For more information on this, refer to Implementing JBIG Features.

JPEG 2000 also supports progressive loading of images. For more information on this, refer to Implementing JPEG 2000 Plug in Features.

The following example shows how to save a progressive LEAD then implement a progressive paint-while-load:

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

1.

First, create a class that derives from LFile. This class will include an override for LFile::LoadFileCallBack.

 

//MyLFile.h
#ifndef _MY_LFILE_H
#define _MY_LFILE_H

#include "d:\lead14\dll\include\classlib\ltwrappr.h"

class LProgressiveFile : public LFile
{
 LEAD_DECLAREOBJECT(LProgressiveFile);
private:
HWND m_hWnd;

protected:
virtual L_INT LoadFileCallBack(
pFILEINFO pFileInfo,
LBitmapBase * pLBitmap,
LBuffer * pLBuffer,
L_UINT uFlags,
L_INT nRow,
L_INT nLines
);

public:
LProgressiveFile();
virtual ~LProgressiveFile();

L_VOID SetDisplayWnd(HWND hWnd);
L_INT LoadFile(
L_INT nBitsPerPixel=0,
L_INT nOrder=ORDER_BGRORGRAY,
L_UINT uFlags=LOADFILE_ALLOCATE | LOADFILE_STORE,
pLOADFILEOPTION pLoadFileOption = NULL
);

L_INT SaveBitmap(
L_INT nFormat,
L_INT nBitsPerPixel=0,
L_INT nQFactor=2,
L_UINT uFlags=SAVE_OVERWRITE,
pSAVEFILEOPTION pSaveFileOption = NULL
);
};

#endif _MY_LFILE_H

 

 

2.

Now, implement the class member functions as follows:

//MyLFile.cpp
#include "MyLFile.h"

LEAD_IMPLEMENTOBJECT(LProgressiveFile)

LProgressiveFile::LProgressiveFile()
{
m_hWnd=0;
}


LProgressiveFile::~LProgressiveFile()
{
}

L_VOID LProgressiveFile::SetDisplayWnd(HWND hWnd)
{
m_hWnd=hWnd;
}

L_INT LProgressiveFile::LoadFile(
L_INT nBitsPerPixel,
L_INT nOrder,
L_UINT uFlags,
pLOADFILEOPTION pLoadFileOption
)
{
L_BOOL bTemp;
L_INT nRet;
L_INT iOldPasses;
LOADFILEOPTION LoadFileOption;

if (pLoadFileOption == NULL)
{
LBaseFile::GetDefaultLoadFileOption(&LoadFileOption);
pLoadFileOption = &LoadFileOption;
}

iOldPasses = pLoadFileOption->Passes;
pLoadFileOption->Passes=CALLBACK_WHEN_MEANINGFUL;

if(!IsWindow(m_hWnd))
LEAD_ERROR_RETURN(WRPERR_INVALID_PARAMETERS);

bTemp=EnableCallBack(TRUE);
nRet=LFile::LoadFile(nBitsPerPixel,nOrder,uFlags, pLoadFileOption);
EnableCallBack(bTemp);
pLoadFileOption->Passes = iOldPasses;
return(nRet);
}


L_INT LProgressiveFile::SaveBitmap(
L_INT nFormat,
L_INT nBitsPerPixel,
L_INT nQFactor,
L_UINT uFlags,
pSAVEFILEOPTION pSaveFileOption
)
{
L_INT iOldPasses;
SAVEFILEOPTION SaveFileOption;

if(IsValid())
{
if (pSaveFileOption == NULL)
{
LBaseFile::GetDefaultSaveFileOption(&SaveFileOption);
pSaveFileOption = &SaveFileOption;
}

iOldPasses = pSaveFileOption->Passes;
pSaveFileOption->Passes=8;
}

L_INT nRet = LFile::Save(nFormat,nBitsPerPixel,nQFactor,uFlags,pSaveFileOption);
pSaveFileOption->Passes = iOldPasses;
return nRet;
}


L_INT LProgressiveFile::LoadFileCallBack(
pFILEINFO pFileInfo,
LBitmapBase * pLBitmap,
LBuffer * pLBuffer,
L_UINT uFlags,
L_INT nRow,
L_INT nLines
)
{
LBuffer LBufferExp;
HDC hDC;
RECT Rect;

if(!IsWindow(m_hWnd))
return(SUCCESS);

::GetClientRect(m_hWnd,&Rect);

if(uFlags&FILEREAD_COMPRESSED)
LBufferExp.ExpandRows(*pLBuffer,pLBitmap->GetWidth(),nLines);

hDC=::GetDC(m_hWnd);

pLBitmap->SetSrcRect(&Rect);
pLBitmap->SetClipSrcRect(&Rect);
pLBitmap->SetDstRect(&Rect);
pLBitmap->SetClipDstRect(&Rect);

pLBitmap->Paint()->SetDC(hDC);
pLBitmap->Paint()->PaintDCBuffer(
(uFlags&FILEREAD_COMPRESSED)
?LBufferExp:*pLBuffer,
nRow,nLines
);
pLBitmap->Paint()->SetDC(0);
Sleep(3);

::ReleaseDC(m_hWnd,hDC);
return(SUCCESS);
}

3.

Now, you can use the new class as follows:

L_VOID Example54(HWND hWnd, L_TCHAR * szFilename)
{
LProgressiveFile ProgressiveFile;
LBitmapBase Bitmap;

//load the image
Bitmap.Load(szFilename);
ProgressiveFile.SetBitmap(&Bitmap);
ProgressiveFile.SetFileName(TEXT("d:\\progress.cmp"));

//save the image in progressive format (8 passes)
ProgressiveFile.SaveBitmap(FILE_CMP,24,PQ2);

::InvalidateRect(hWnd,0,TRUE);
::UpdateWindow(hWnd);
//set the window to be used for displaying the progressive image
ProgressiveFile.SetDisplayWnd(hWnd);

//load the progressive file
ProgressiveFile.LoadFile(0,ORDER_BGR,LOADFILE_ALLOCATE|LOADFILE_STORE);
}