Click here to Skip to main content
15,906,558 members
Articles / Desktop Programming / MFC
Article

CxImage

Rate me:
Please Sign up or sign in to vote.
4.65/5 (949 votes)
15 Feb 2008Zlib13 min read 13.4M   300.7K   1.6K   3.9K
CxImage is a C++ class to load, save, display, transform BMP, JPEG, GIF, PNG, TIFF, MNG, ICO, PCX, TGA, WMF, WBMP, JBG, J2K images.

Image 1

Preface

Years after the previous version, I can tell that the article has survived its author, and even if my opinion on the limits of this library has not changed, an update was really necessary.

Thank you very much to all the people that gave their contribution to this new release, with hundreds of small and big enhancements, my role was mainly to put all the pieces together.

Introduction & License

CxImage is a C++ class that can load, save, display, and transform images in a very simple and fast way.

The class CxImage is free; as for the TIFF, JPEG, PNG and ZLIB libraries : "If you use this source code in a product, acknowledgement is not required but would be appreciated."

CxImage is open source and licensed under the zlib license . In a nutshell, this means that you can use the code however you wish, as long as you don't claim it as your own.

What's New in Version 6.00

The complete list of bugfixes and enhancements is reported in the documentation, (see \doc\cximage_history.htm, or this link). Here I will highlight some of the new features.

An application written with CxImage version 5.99 should work also with the new version; the interface of few methods is different, normally because of new parameters, but the default behaviour is the same.

The applications linked with the old DLL will not work with the new one; but if necessary you can edit the declarations, or add new overloads, and revert to the old interface for the DLL. An issue to take care is ENUM_CXIMAGE_FORMATS: in the old version the CXIMAGE_FORMAT_... can change the value, depending on the supported formats enabled by the corresponding CXIMAGE_SUPPORT_... switch. In the new version, CXIMAGE_FORMAT_... are assigned to unique values. Static methods like GetNumTypes, GetTypeIdFromName, GetTypeIdFromIndex, GetTypeIndexFromId will help the application to manage the new policy.

File Formats & Linked C Libraries

CxImage works with the latest version of these libraries: Zlib (1.2.3), Jasper ( 1.900.1), LibMNG (1.0.10), LibPNG (1.2.24). LibTIFF 3.8.2 can be linked with CxImage, but the version included in the CxImage distribution (3.5.7, patched) can read images with OJPEG compression, or with non standard bit per samples. The choice is up to you.

The j2k library (now openjpeg), and the associated class CxImageJ2K, have been removed from the project. JPEG2000 images are supported through Jasper and CxImageJAS.

CxImage 6.00 includes a new class (CxImageRAW) and a new library (LibDCR) to read RAW images from digital cameras; common file extension are: RAW, CRW, NEF, CR2, DNG, ORF, ARW, ERF, 3FR, DCR, X3F, MEF, RAF, MRW, PEF, SR2. LibDCR is based on Dave Coffin's dcraw.c; and offers the same features of the original dcraw application (see the "dcr.dsw" project included in the \raw directory). The restricted features under the GPL Version 2 are disabled; please read the license terms in "libdcr.h" before enabling the restricted code.

CxImageRAW implements the basic functions to decode the image, the only available option controlled by SetCodecOption, is about the interpolation quality (DECODE_QUALITY_LIN=0, DECODE_QUALITY_VNG=1, DECODE_QUALITY_PPG=2, DECODE_QUALITY_AHD=3).

CxImagePNG has been improved to read and write all of the PNG_COLOR_TYPE_... combinations. PNGs with a "pixel depth" more that 8 bits per channel will be converted down to 8 bits, this is the major limit in CxImage.

CxImageGIF: better support for reading animated GIF, now can decode all frames in a single pass, if enabled with SetRetreiveAllFrames. The CxImage demo implements this option, and shows how to play an animated GIF (when the program asks "File with N images. Read all?", select "Cancel").

CxImageBMP: reads and writes 32 bit images (with alpha layer).
CxImageICO: reads and writes Vista (PNG) icons; and added support for writing multipage icons.
CxImageMNG: reads MNGs with alpha layer.
CxImageSKA: new class for SKA image format, used in some video rental application.

CxImageJPG: new options for the JPEG format subsampling (ENCODE_SUBSAMPLE_422, ENCODE_SUBSAMPLE_444), default is 4:1:1 (high), can be set to 4:2:2 (medium) or 4:4:4 (none).

The next table shows the different amount of artifacts in the compressed image, using to different subsampling. 4:4:4 subsampling is useful in images with sharp edges, to reduce the typical blurring effect of the JPG compression.

Image 2
original image
Image 3 Image 4
JPG image and artefacts,
quality 75, subsampling 4:1:1
Image 5 Image 6
JPG image and artefacts,
quality 75, subsampling 4:4:4

Portability

The class and the projects have been tested with different compilers, from Microsoft VC++6 to VC++2008, with Borland C++ Builder 3 and 6, and partially with wxDev-C++ and MinGW.

UNICODE and non-UNICODE configurations are provided for all the libraries (thanks to Eric Jesover).

A light version (cximage600_lite) without the C libraries and with a small demo is provided for the first time users, or as a basic template, without the clutter of the full demo project.

The console (\demo2) and the CxImageCrtDll projects can be built with VC++Express2005 and the Microsoft Platform SDK. If you get linker errors like "unresolved external...", check if all the C libraries have been compiled (set the correct project dependencies), or add the gdi32.lib and user32.lib modules to the Linker\Input\Additional Dependencies property.

CxImage works also with Pocket PC 2003; a working version and demo (cximage600_ce) are provided for the VC++2005 compiler (thanks to Vincent Richomme). For the old embedded VC compilers, the main limit was the support for exception handling. To overcome this problem, the try, throw and catch statements have been replaced with 3 macros (defined in ximadef.h), and with the definition of CXIMAGE_SUPPORT_EXCEPTION_HANDLING; in this way it is possible to build the library without exception handling support. Maybe the solution is not so elegant, but the impact on the source code is minimal when exception handling is disabled, while there are no changes in case of exception handling enabled.

The compatibility between little-endian and big-endian platforms, for the built in formats (bmp, ico, tga, pcx, gif, ska) is handled by ntohs and ntohl.

Demo

Almost all the new features can be tested in the main CxImage demo application. The demo is just a test bench, even if it offers some nice features, it is not intended to be a serious application.

  • CQuantizer : the class is used with the DecreaseBpp menu. In the previous version there was a rounding error, clearly visible when in some case the white colour (255,255,255) was converted to (254,254,254). In the new release this error has been fixed.
  • Copy/Paste : now pastes also metafile pictures (for example, from Office applications). The demo internally uses a custom clipboard format, to test the Dump/Undump methods.
    Copy works on the active selection, use \CxImage\Remove Selection to copy the full image.
  • FloodFill : (\View\Tools\Flood Fill) with a floating dialog, you can test the FloodFill colour, tolerance, opacity, and selection. The case with opacity = 0 and selection enabled acts as a "magic wand".
  • Graph data extraction : (\Filters\graph data extraction) extracts the numeric data from graphs (acquired from scanners or downloaded from the internet). The converted values are pasted into the clipboard, and can be saved to text or Excel files.
    Image 7
    Data Extraction dialog and results

    Image 8

  • RedEyeRemove : (\Filters\Non Linear\Remove Red Eye) removes the red-eye effect that frequently occurs in pictures. You must select the region around the pupil, where the function will filter the red channel. The selection can also be rectangular, or including part of the iris: the filter works on a circular region centred on the selection.
    Image 9
    original image
    Image 10
    selection around the pupil
    Image 11
    result after RedEyeRemove
  • SelectiveBlur / UnsharpMask : these non linear filters increase the image quality. SelectiveBlur removes the "granular" noise (jpeg artefacts, or digital camera noise) preserving the details, UnsharpMask enhances the details without adding noise in the "flat" regions.
  • Custom linear filters : (\Filters\Linear\Custom) a small graphic interface to test new kernels for the Filter function (thanks to Priyank Bolia).
  • Histogram : (\Colors\Histogram\...) many menus are available to test HistogramStretch with different approaches (0 = luminance, 1 = linked channels , 2 = independent channels); the threshold parameter increases the robustness of the algorithm in case of noisy images. "Half Saturation" and "Full Saturation" test the combination of ConvertColorSpace, Histogram, and Saturate, to stretch the histogram in the YUV colorspace.
    Image 12
    original image
    Image 13
    + HistogramStretch(2,0.005f)
    Image 14
    + "Half saturation"
  • Thresholding : ( \Colors\Threshold... and \Colors\Adaptive Threshold). OptimalThreshold is a new method to find the optimal threshold for image binarization, the available algorithms are:
    1 = Otsu;
    2 = Kittler & Illingworth;
    3 = maximum entropy;
    4 = potential difference;
    0 = average all methods (default, and used in the demo);

    The option "preserve colors less than the threshold" will test Threshold2, useful to filter colored images with a noisy background, the result will be a colored image with a uniform background.
    AdaptiveThreshold is an application of OptimalThreshold to build a variable threshold mask. AdaptiveThreshold is useful in case of images with a non uniform lightness, where a single threshold can't be optimal for the whole image; but in general it will give bad results if the parameters are not well tuned.

    Image 15
    original image

    Image 16
    OptimalThreshold + Threshold

    Image 17
    AdaptiveThreshold

  • Add shadow : (\Filters\Add Shadow...) this menu is a small example on how the simple CxImage methods (selections, GaussianBlur, Mix) can be combined to obtain a common effect.
    Image 18
    purple shadow on white background
    Image 19
    black shadow on red background
  • Text smoothing : DrawStringEx implements a new option, through CXTEXTINFO::smooth, that can be tested with the text tool (\View\Tools\Text), checking the "antialias" option.

    A similar effect can be obtained in post processing with TextBlur (\Filters\Non Linear\Text Blur): a non linear filter that works only on diagonal or round edges, without affecting vertical or horizontal lines. In the next table there is a comparison between different smoothing methods:

    Image 20
    DrawStringEx without smoothing
    Image 21
    DrawStringEx with smoothing
    Image 22
    post processing with TextBlur
    Image 23
    post processing with a linear 3x3 "soften" Filter

CxImage Structure

In the vertical hierarchy of the library, CxImage stays on the top of the other modules, it's not a clean OOP approach, but the result was good since the first release and now it's too late to change again. Anyway you can always use the derived classes to perform the format specific operations, like for CxImageTIF to save multipage TIFFs.

The glue to connect all the modules and the C libraries is CxFile, a virtual class that provides the standard methods to access the data from a file on the disk or in memory.

Image 24

A Cximage object is basically a bitmap, with the addition of some member variables to store useful information:

class CxImage
 {
 ...
 protected:
 void* pDib;            //contains the header, the palette, the pixels
 BITMAPINFOHEADER head; //standard header
 CXIMAGEINFO info;      //extended information
 BYTE* pSelection;      //selected region
 BYTE* pAlpha;          //alpha channel
 CxImage** ppLayers;     //generic layers
 CxImage** ppFrames;     //frames for animation
 }

CxImage::head is the bitmap header and CxImage::pDib is a normal bitmap (as you can see in the implementation of CxImageBMP::Encode).

CxImage::info is a handy container of many information shared between different formats, and for all the member functions.

typedef struct tagCxImageInfo {
    DWORD   dwEffWidth;       //DWORD aligned scan line width
    BYTE*   pImage;           //THE IMAGE BITS
    void*   pGhost;           //if this is a ghost, pGhost point to the body
    DWORD   dwType;           //original image format
    char    szLastError[256]; //debugging
    long    nProgress;        //monitor
    long    nEscape;          //escape
    long    nBkgndIndex;      //used for GIF, PNG, MNG
    RGBQUAD nBkgndColor;      //used for RGB transparency
    BYTE    nQuality;         //used for JPEG
    long    nFrame;           //used for TIF, GIF, MNG : actual frame
    long    nNumFrames;       //used for TIF, GIF, MNG : total number of 
                              //frames
    DWORD   dwFrameDelay;     //used for GIF, MNG
    long    xDPI;             //horizontal resolution
    long    yDPI;             //vertical resolution
    RECT    rSelectionBox;    //bounding rectangle
    BYTE    nAlphaMax;        //max opacity (fade)
    bool    bAlphaPaletteEnabled;  //true if alpha values in the palette are 
                              // enabled.
    bool    bEnabled;         //enables the painting functions
    long    xOffset;
    long    yOffset;
    DWORD   dwEncodeOption;   //for GIF, TIF : 0=def.1=unc,2=fax3,3=fax4,
                              // 4=pack,5=jpg
    RGBQUAD last_c;           //for GetNearestIndex optimization
    BYTE    last_c_index;
    bool    last_c_isvalid;
    long    nNumLayers;
    DWORD   dwFlags;
} CXIMAGEINFO;

A CxImage object is also a set of layers. The buffers in each layer are allocated only when necessary.

Image 25

CxImage::pDib is the background image. CxImage::pAlpha is the transparency layer. CxImage::pSelection is the selection layer, used to create regions of interest for image processing. Over these 3 specific planes, you can add other generic layers, stored in CxImage::ppLayers. The generic layers are full CxImage objects, so you can build complex structures of nested layers. CxImage::ppFrames is reserved for animated images (GIF)

CxImage Class Members & Operations

CxImage is documented using Doxygen , however for historical reasons, many uncommon features are still undocumented. The class members reference, together with release history, and license, can be found here

Supported Formats and Options

The whole library is quite big, in the main header file ximcfg.h you'll find the switches to enable or disable a specific graphic format or feature. Each JPG, PNG and TIFF library adds about 100KB to the final application, while the CxImage impact is about 50KB. So you should support and link only the formats that your application really needs.

formats#definerequired librariessize [Kbyte]
BMP
GIF
ICO
TGA
PCX
WBMP
WMF
SKA
CXIMAGE_SUPPORT_BMP<br />CXIMAGE_SUPPORT_GIF<br />CXIMAGE_SUPPORT_ICO<br />CXIMAGE_SUPPORT_TGA<br />CXIMAGE_SUPPORT_PCX<br />CXIMAGE_SUPPORT_WBMP<br />CXIMAGE_SUPPORT_WMF<br />CXIMAGE_SUPPORT_SKA
built in

24
JPEGCXIMAGE_SUPPORT_JPG
jpeg

88
PNGCXIMAGE_SUPPORT_PNG
png, zlib

104
MNGCXIMAGE_SUPPORT_MNG
mng, zlib, jpeg

148
TIFFCXIMAGE_SUPPORT_TIF
tiff, zlib, jpeg

124
JBIGCXIMAGE_SUPPORT_JBG
jbig

28
PNM,PPM,PGM
RAS
CXIMAGE_SUPPORT_PNM<br />CXIMAGE_SUPPORT_RAS
jasper

176
JPEG-2000CXIMAGE_SUPPORT_JP2<br />CXIMAGE_SUPPORT_JPC<br />CXIMAGE_SUPPORT_PGX
jasper

176
RAWCXIMAGE_SUPPORT_RAWlibdcr132

Option#defineSize [Kbyte]
CxImage coreall switches off20
geometric transformationsCXIMAGE_SUPPORT_TRANSFORMATION16
image processingCXIMAGE_SUPPORT_DSP24
drawing and windows specific functionsCXIMAGE_SUPPORT_WINDOWS12
transparencyCXIMAGE_SUPPORT_ALPHA4
selectionsCXIMAGE_SUPPORT_SELECTION4
multiple layersCXIMAGE_SUPPORT_LAYERS< 4
graphic formats conversionCXIMAGE_SUPPORT_DECODE<br />CXIMAGE_SUPPORT_ENCODE < 4
interpolation functions CXIMAGE_SUPPORT_INTERPOLATION< 4
exception handling CXIMAGE_SUPPORT_EXCEPTION_HANDLING< 4

Using CxImage in your Projects

The CxImgLib.dsw workspace shows the libraries required to build an application (demo.exe) including almost all the features and the formats available in CxImage. You must compile all the libraries before you can link the final application.
In the same workspace you'll find the projects to build different libraries and applications:

  • CxImage : cximage.lib - static library
  • CxImageCrtDll : cximagecrt.dll - DLL not using mfc
  • CxImageMfcDll : cximage.dll - DLL using mfc
  • Demo : demo.exe - program linked with cximage.lib and the C libraries
  • DemoDll : demodll.exe - program linked with cximagecrt.dll
  • libdcr,jasper,jbig,jpeg,png,tiff,zlib : static C libraries

Building the projects will need some minutes to complete. When everything is done, select the demo project and launch the application.

CxImgLib.dsw
Image 26

To use CxImage in your project, you must edit these settings:

Project Settings
 |- C/C++
 |   |- Code Generation
 |   |   |- Use run-time library : Multithreaded DLL (must be the same for 
 |   |   |  all the linked libraries)
 |   |   |- Struct member alignment : must be the same for all the linked 
 |   |   |  libraries
 |   |- Precompiled headers : not using precompiled headers
 |   |- Preprocessor
 |       |- Additional Include Directories:  ..\cximage
 |- Link
    |- General
        |- Object/library modules: ../png/Debug/png.lib  
                                   ../raw/Debug/libdcr.lib
                                   ../jpeg/Debug/jpeg.lib 
                                   ../zlib/Debug/zlib.lib 
                                   ../tiff/Debug/tiff.lib
                                   ../jasper/Debug/jasper.lib
                                   ../cximage/Debug/cximage.lib  ...

In your source code you must add #include "ximage.h"

Note: don't mix debug and release modules; each configuration must use its respective library modules.

Adding your Custom Functions in CxImage

Writing a new function for image processing is not so hard with CxImage. Here I'm going to describe CxImage::Jitter — it's very simple but it shows many aspects to take care of when you work inside CxImage. The first thing, of course, is the declaration : bool Jitter(long radius=2); in the CXIMAGE_SUPPORT_DSP section of ximage.h, you can declare the function everywhere in the public scope of the class. And now the definition:

C++
bool CxImage::Jitter(long radius)
{
    // check if the image is valid, this should be always the first line in 
    // the function 
    if (!pDib) return false;
    
    // local variables
    long nx,ny;
    
    // temporary image to store the partial results of the algorithm
    CxImage tmp(*this,pSelection!=0,true,true);
    
    // limit the effects of the functions only in the smallest rectangle that
    // holds the selected region (defined with the Selection...() functions ),
    // this will speed up the loops.
    long xmin,xmax,ymin,ymax;
    if (pSelection){
        xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;
        ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;
    } else {
        xmin = ymin = 0;
        xmax = head.biWidth; ymax=head.biHeight;
    }
    
    // main loop : scan the image in vertical direction
    for(long y=ymin; y <ymax; y++){
    
        // monitor the progress of the loops
        info.nProgress = (long)(100*y/head.biHeight);
    
        // let the application a way to exit quickly
        if (info.nEscape) break;
    
        // main loop : scan the image in horizontal direction
        for(long x=xmin; x<xmax; x++){
    
        // if the feature is enabled, process only the pixels inside the 
        // selected region
#if CXIMAGE_SUPPORT_SELECTION
            if (SelectionIsInside(x,y))
#endif //CXIMAGE_SUPPORT_SELECTION
            {
                // main algorithm
                nx=x+(long)((rand()/(float)RAND_MAX - 0.5)*(radius*2));
                ny=y+(long)((rand()/(float)RAND_MAX - 0.5)*(radius*2));
                if (!IsInside(nx,ny)) {
                    nx=x;
                    ny=y;
                }

                // save the result in the temporary image.
                // if you can, use PixelColor only for 24 bpp images,
                // and PixelIndex for 8, 4 and 1 bpp images : it's faster
                if (head.biClrUsed==0){
                    tmp.SetPixelColor(x,y,GetPixelColor(nx,ny));
                } else {
                    tmp.SetPixelIndex(x,y,GetPixelIndex(nx,ny));
                }

                // if the feature is enabled, process also the pixels 
                // in the alpha layer
#if CXIMAGE_SUPPORT_ALPHA
                tmp.AlphaSet(x,y,AlphaGet(nx,ny));
#endif //CXIMAGE_SUPPORT_ALPHA

            }
        }
    }

    // save the result and exit
    Transfer(tmp);
    return true;
}

Examples: How to ...

... Convert from One Format to Another

C++
CxImage  image;
// bmp -> jpg


image.Load("image.bmp", CXIMAGE_FORMAT_BMP);
if (image.IsValid()){
    if(!image.IsGrayScale()) image.IncreaseBpp(24);
    image.SetJpegQuality(80);
    image.Save("image.jpg",CXIMAGE_FORMAT_JPG);
}
// png -> tif


image.Load("image.png", CXIMAGE_FORMAT_PNG);
if (image.IsValid()){
    image.Save("image.tif",CXIMAGE_FORMAT_TIF);
}

... Load an Image Resource

C++
//Load the resource IDR_PNG1 from the PNG resource type


CxImage* newImage = new CxImage();
newImage->LoadResource(FindResource(NULL,MAKEINTRESOURCE(IDR_PNG1),
                       "PNG"),CXIMAGE_FORMAT_PNG);
or
C++
//Load the resource IDR_JPG1 from DLL




CxImage* newImage = new CxImage();
HINSTANCE hdll=LoadLibrary("imagelib.dll");

if (hdll){
    HRSRC hres=FindResource(hdll,MAKEINTRESOURCE(IDR_JPG1),"JPG");
    newImage->LoadResource(hres,CXIMAGE_FORMAT_JPG,hdll);
    FreeLibrary(hdll);
}
or
C++
//Load a bitmap resource;

HBITMAP bitmap = ::LoadBitmap(AfxGetInstanceHandle(),
                              MAKEINTRESOURCE(IDB_BITMAP1)));
CxImage *newImage = new CxImage();
newImage->CreateFromHBITMAP(bitmap);

... Decode an Image from Memory

C++
CxImage image((BYTE*)buffer,size,image_type);
or
C++
CxMemFile memfile((BYTE*)buffer,size);
CxImage image(&memfile,image_type);
or
C++
CxMemFile memfile((BYTE*)buffer,size);
CxImage* image = new CxImage();
image->Decode(&memfile,type);

... Encode an Image in Memory

C++
long size=0;
BYTE* buffer=0;
image.Encode(buffer,size,image_type);
...
image.FreeMemory(buffer);
or
CxMemFile memfile;
memfile.Open();
image.Encode(&memfile,image_type);
BYTE* buffer = memfile.GetBuffer();
long size = memfile.Size();
...
image.FreeMemory(buffer);

... Create a Multipage TIFF

C++
CxImage *pimage[3];
pimage[0]=&image1;
pimage[1]=&image2;
pimage[2]=&image3;

FILE* hFile;
hFile = fopen("multipage.tif","w+b");

CxImageTIF multiimage;
multiimage.Encode(hFile,pimage,3);

fclose(hFile);
or
C++
FILE* hFile;
hFile = fopen("c:\\multi.tif","w+b");

CxImageTIF image;
image.Load("c:\\1.tif",CXIMAGE_FORMAT_TIF);
image.Encode(hFile,true);
image.Load("c:\\2.bmp",CXIMAGE_FORMAT_BMP);
image.Encode(hFile,true);
image.Load("c:\\3.png",CXIMAGE_FORMAT_PNG);
image.Encode(hFile);

fclose(hFile);

... Copy/Paste an Image

C++
//copy

HANDLE hDIB = image->CopyToHandle();
if (::OpenClipboard(AfxGetApp()->m_pMainWnd->GetSafeHwnd())) {
    if(::EmptyClipboard()) {
        if (::SetClipboardData(CF_DIB,hDIB) == NULL ) {
            AfxMessageBox( "Unable to set Clipboard data" );
}    }    }
CloseClipboard();


//paste

HANDLE hBitmap=NULL;
CxImage *newima = new CxImage();
if (OpenClipboard()) hBitmap=GetClipboardData(CF_DIB);
if (hBitmap) newima->CreateFromHANDLE(hBitmap);
CloseClipboard();

... Display a File in a Picture Box

C++
HBITMAP m_bitmap = NULL;
CxImage image("myfile.png", CXIMAGE_FORMAT_PNG);
...
CDC* hdc = m_picture.GetDC();
HBITMAP m_bitmap = image.MakeBitmap(hdc->m_hDC);

HBITMAP hOldBmp = m_picture.SetBitmap(m_bitmap);
if (hOldBmp) DeleteObject(hOldBmp);
if (hdc->m_hDC) m_picture.ReleaseDC(hdc);
...
if (m_bitmap) DeleteObject(m_bitmap);

History and Credits

Starting form my CxDib class, that implements memory DIBs only, I tried to add some members to read images from files. Looking for a solution, I found a nice MFC class named CImage on the net, release 1.4 (1998). CImage supports BMP, GIF, PNG and JPG, but suffers many little bugs and uses a complex class structure, so I decided to strip it to the base and merge CxDib with the CImage philosophy, to obtain the new CxImage class. Also I updated the libraries for JPG, PNG and ZLIB.

With CxImage it is very easy to add new image types, so I added the TIFF library (rev. 6) and a minimal support for ICONs, MNG, TGA and PCX. Finally I added some specific functions to obtain an image from global HANDLEs (windows clipboard) and objects (windows resources). This is the story until the early release, the following is written in the documentation.

  • CImage © 1995-1998, Alejandro Aguilar Sierra.
  • IJG JPEG library ©1994-1998, Thomas G. Lane.
  • LibPNG version 1.2.7© 1998-2007 Glenn Randers-Pehrson
  • LibTIFF version 3.5.7 © 1988-1997 Sam Leffler, © 1991-1997 Silicon Graphics, Inc.
  • LibMNG version 1.0.10 © 2000,2002 Gerard Juyn.
  • Gif-RLE © Hutchison Avenue Software Corporation, 1998
  • LibJ2K© David Janssens, 2001 - 2002
  • LibJBG version 1.6 © Markus Kuhn, 2004
  • JasPer version 1.900.1 © Image Power, UBC, Michael David Adams, 2001 - 2007
  • zlib version 1.2.3 © 1995-2005 Jean-loup Gailly and Mark Adler
  • Thanks to Troels Knakkergaard for his precious work in the earlier versions of CxImage, Rajiv Ramachandran for CTwain code; to Abe for multi page tiffs code; to Chris Shearer Cooper for memory file suggestions and code; to Brent Corkum for BCMenu code.

More specific credits and disclaimers are in every header file of each library.

License

This article, along with any associated source code and files, is licensed under The zlib/libpng License


Written By
Italy Italy
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralRe: tutorial? Pin
hurr1can319-Jan-04 6:39
hurr1can319-Jan-04 6:39 
GeneralRe: tutorial? Pin
Davide Pizzolato19-Jan-04 9:32
Davide Pizzolato19-Jan-04 9:32 
GeneralRe: tutorial? Pin
hurr1can319-Jan-04 22:13
hurr1can319-Jan-04 22:13 
GeneralRe: tutorial? Pin
moe200420-Jan-04 2:43
moe200420-Jan-04 2:43 
GeneralRe: tutorial? Pin
hurr1can321-Jan-04 4:08
hurr1can321-Jan-04 4:08 
GeneralRe: tutorial? Pin
Davide Pizzolato21-Jan-04 8:49
Davide Pizzolato21-Jan-04 8:49 
GeneralRe: tutorial? Pin
hurr1can321-Jan-04 15:04
hurr1can321-Jan-04 15:04 
Generalinterface with Rogue Wave Stingray Studio Pin
alexander chupeev15-Jan-04 7:27
alexander chupeev15-Jan-04 7:27 
Hi,

I propose an implementation of stingray::foundation::SECImage and
all derived classes that utilizes CxImage library. This stuff
should be used in place of original code and provides the following
advatages:
-- ripped dependency from open source libraries so they can
be updated independently from RWSS code
-- has whole functionality of Stingray extension image classes
that does not suffer from patent limitations
-- in my humble opinion, CxImage library is written much better
then RWSS original code

Alexander

------------------- SECImage.h ------------------------
#ifndef __SECIMAGE_H__
#define __SECIMAGE_H__

#ifdef _SFLDLL
#undef AFXAPP_DATA
#define AFXAPP_DATA AFXAPI_DATA
#undef AFX_DATA
#define AFX_DATA SFL_DATAEXT
#endif //_SFLDLL

#include <ximage.h>

namespace stingray {
namespace foundation {

class SECImage : public CObject
{
public:
SECImage();

DWORD dwGetWidth() const;
DWORD dwGetHeight() const;
BOOL CopyImage(SECImage *pSrc);
BOOL ConvertImage(SECImage *pSrc);
CBitmap* MakeBitmap(CDC *pDC, const TCHAR *lpszFileName);
CBitmap* MakeBitmap(CDC *pDC);
virtual BOOL LoadImage(CFile* pFile);
virtual BOOL LoadImage(LPCTSTR lpszFileName);
virtual BOOL SaveImage(CFile* pFile);
virtual BOOL SaveImage(LPCTSTR lpszFileName);
BOOL FlipHorz();
BOOL FlipVert();
BOOL Rotate90(BOOL bClockwise=TRUE);
void ContrastImage(short nSharpen);
BOOL Crop(long nLeft, long nTop, long nWidth, long nHeight);
DWORD NumBytes() const;
WORD NumColors() const;
int StretchDIBits(CDC *pDC, int XDest, int YDest, int cxDest, int cyDest,
int XSrc, int YSrc, int cxSrc, int cySrc, const void* lpvBits,
LPBITMAPINFO lpbmi, UINT fuColorUse, DWORD fdwRop);
BOOL CreateFromBitmap(CDC *pDC, CBitmap *pSrcBitmap);
static SECImage* ParseImage(LPCTSTR lpszPathName);
static SECImage* ParseImage(CFile* pFile);
CPalette* GetPalette();

void Serialize(CArchive &ar);
virtual ~SECImage();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif //_DEBUG

protected:
CxImage* m_pImage;

virtual BOOL CreatePalette();
virtual BOOL PreLoadImage();
virtual BOOL PostLoadImage();
virtual BOOL PreSaveImage();
virtual BOOL PostSaveImage();
virtual BOOL DoSaveImage(CFile* pFile);
virtual BOOL DoLoadImage(CFile* pFile);

// for compatibility with RWSS
public:
CPalette* m_pPalette; // a pointer to the palette for image
LPBYTE m_lpSrcBits; // the image data (flat buffer)
LPBITMAPINFO m_lpBMI; // a pointer to the BITMAPINFO buffer
};

class SECDib: public SECImage
{
DECLARE_SERIAL(SECDib)

public:
SECDib();
virtual ~SECDib();
void Serialize(CArchive& ar);
#ifdef _DEBUG
void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif

protected:
virtual BOOL DoSaveImage(CFile* pFile);
virtual BOOL DoLoadImage(CFile* pFile);
};

class SECJpeg: public SECImage
{
DECLARE_SERIAL(SECJpeg)
public:
SECJpeg();
virtual ~SECJpeg();
void Serialize(CArchive& ar);
#ifdef _DEBUG
void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif

BOOL m_bQuantize;
long m_nQuality;
long m_nSmoothing;
BOOL m_bOptimizeEntropyCoding;
BOOL m_bArithmeticCoding;

protected:
virtual BOOL DoSaveImage(CFile* pFile);
virtual BOOL DoLoadImage(CFile* pFile);
};

} // namespace stingray::foundation
} // namespace stingray

class SECGif: public stingray::foundation::SECImage
{
DECLARE_SERIAL(SECGif)

public:
SECGif();
virtual ~SECGif();
void Serialize(CArchive& ar);
#ifdef _DEBUG
void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif

void SetTransparent(BOOL bArg);
BOOL GetTransparent();
void SetTransparentColors(BYTE cRed, BYTE cGreen, BYTE cBlue);
COLORREF GetTransparentColor();
void SetInterlace(BOOL bArg);
BOOL GetInterlaced();

protected:
virtual BOOL DoSaveImage(CFile* pFile);
virtual BOOL DoLoadImage(CFile* pFile);
};

class SECPcx: public stingray::foundation::SECImage
{
DECLARE_SERIAL(SECPcx)

public:
SECPcx();
virtual ~SECPcx();
void Serialize(CArchive& ar);
#ifdef _DEBUG
void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif

protected:
virtual BOOL DoSaveImage(CFile* pFile);
virtual BOOL DoLoadImage(CFile* pFile);
};

class SECTarga: public stingray::foundation::SECImage
{
DECLARE_SERIAL(SECTarga)

public:
SECTarga();
virtual ~SECTarga();
void Serialize(CArchive& ar);
#ifdef _DEBUG
void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif

protected:
virtual BOOL DoSaveImage(CFile* pFile);
virtual BOOL DoLoadImage(CFile* pFile);
};

class SECTiff: public stingray::foundation::SECImage
{
DECLARE_SERIAL(SECTiff)

public:
SECTiff();
virtual ~SECTiff();
void Serialize(CArchive& ar);
#ifdef _DEBUG
void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif

protected:
virtual BOOL DoSaveImage(CFile* pFile);
virtual BOOL DoLoadImage(CFile* pFile);
};

//////////////////////////////////////////////////////
// Promote the operator>> symbol declared by the
// DECLARE_SERIAL macro to the global namespace.
using stingray::foundation::operator>>;
//////////////////////////////////////////////////////

#undef AFX_DATA
#define AFX_DATA
#undef AFXAPP_DATA
#define AFXAPP_DATA NEAR

#endif

-------------------- SECImage.cpp ----------------------
#include "stdafx.h"

#ifdef _SFL_MFC_SUPPORT

#include <ximabmp.h>
#include <ximajpg.h>
#include <ximagif.h>
#include <ximapcx.h>
#include <ximatga.h>
#include <ximatif.h>

#ifdef _SFLDLL
#undef AFXAPI_DATA
#define AFXAPI_DATA __based(__segname("_DATA"))
#endif //_SFLDLL

#include "Foundation\Image\MFC\SECImage.h"

#ifdef _SFLDLL
#undef AFXAPP_DATA
#define AFXAPP_DATA AFXAPI_DATA
#endif //_SFLDLL

#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif

#define new DEBUG_NEW

class CImage_File: public CxFile
{
public:
CImage_File(CFile* pFile);
virtual ~CImage_File();
virtual bool Close();
virtual size_t Read(void* buffer, size_t size, size_t count);
virtual size_t Write(const void* buffer, size_t size, size_t count);
virtual bool Seek(long offset, int origin);
virtual long Tell();
virtual long Size();
virtual bool Flush();
virtual bool Eof();
virtual long Error();
virtual bool PutC(unsigned char c);
virtual long GetC();
bool Open(LPCTSTR lpszFileName, UINT nOpenFlags, CFileException* pError = 0);
private:
CFile* m_pFile;
};

CImage_File::CImage_File(CFile* pFile): m_pFile(pFile)
{
}

CImage_File::~CImage_File()
{
}

bool CImage_File::Open(LPCTSTR lpszFileName, UINT nOpenFlags, CFileException* pError)
{
return (m_pFile->Open(lpszFileName, nOpenFlags, pError) == TRUE);
}

bool CImage_File::Close()
{
if (m_pFile->m_hFile != CFile::hFileNull)
m_pFile->Close();
return true;
}

size_t CImage_File::Read(void* buffer, size_t size, size_t count)
{
try
{
return m_pFile->Read(buffer, size * count);
}
catch (CFileException&)
{
}
return 0;
}

size_t CImage_File::Write(const void* buffer, size_t size, size_t count)
{
try
{
m_pFile->Write(buffer, size * count);
}
catch(CFileException&)
{
return 0;
}
return size * count;
}

bool CImage_File::Seek(long offset, int origin)
{
try
{
UINT nFrom;
switch (origin)
{
case SEEK_SET:
nFrom = CFile::begin;
break;

case SEEK_CUR:
nFrom = CFile::current;
break;

case SEEK_END:
nFrom = CFile::end;
break;

default:
nFrom = CFile::begin;
}

m_pFile->Seek(offset, nFrom);
}
catch (CFileException&)
{
return false;
}
return true;
}

long CImage_File::Tell()
{
try
{
return (long) m_pFile->GetPosition();
}
catch (CFileException&)
{
}
return 0;
}

long CImage_File::Size()
{
try
{
return (long) m_pFile->GetLength();
}
catch (CFileException&)
{
}
return 0;
}

bool CImage_File::Flush()
{
try
{
m_pFile->Flush();
}
catch (CFileException&)
{
return false;
}
return true;
}

bool CImage_File::Eof()
{
return (Tell() >= Size());
}

long CImage_File::Error()
{
return GetLastError();
}

bool CImage_File::PutC(unsigned char c)
{
return (1 == Write(&c, 1, 1));
}

long CImage_File::GetC()
{
unsigned char c;
return (1 == Read(&c, 1, 1)? c: EOF);
}

class CImage_Archive: public CxFile
{
public:
CImage_Archive(CArchive& arg);
virtual ~CImage_Archive();
virtual bool Close();
virtual size_t Read(void* buffer, size_t size, size_t count);
virtual size_t Write(const void* buffer, size_t size, size_t count);
virtual bool Seek(long offset, int origin);
virtual long Tell();
virtual long Size();
virtual bool Flush();
virtual bool Eof();
virtual long Error();
virtual bool PutC(unsigned char c);
virtual long GetC();
bool Open(LPCTSTR lpszFileName, UINT nOpenFlags, CFileException* pError = 0);
private:
CArchive& ar;
};

CImage_Archive::CImage_Archive(CArchive& a): ar(a)
{
}

CImage_Archive::~CImage_Archive()
{
}

bool CImage_Archive::Open(LPCTSTR lpszFileName, UINT nOpenFlags, CFileException* pError)
{
return false;
}

bool CImage_Archive::Close()
{
return false;
}

size_t CImage_Archive::Read(void* buffer, size_t size, size_t count)
{
if (ar.IsLoading())
{
try
{
return ar.Read(buffer, size * count);
}
catch (CFileException&)
{
}
catch (CArchiveException&)
{
}
}
return 0;
}

size_t CImage_Archive::Write(const void* buffer, size_t size, size_t count)
{
if (ar.IsStoring())
{
try
{
ar.Write(buffer, size * count);
return size * count;
}
catch(CFileException&)
{
return 0;
}
catch(CArchiveException&)
{
}
}
return 0;
}

bool CImage_Archive::Seek(long offset, int origin)
{
return false;
}

long CImage_Archive::Tell()
{
return -1;
}

long CImage_Archive::Size()
{
return -1;
}

bool CImage_Archive::Flush()
{
return false;
}

bool CImage_Archive::Eof()
{
return false;
}

long CImage_Archive::Error()
{
return GetLastError();
}

bool CImage_Archive::PutC(unsigned char c)
{
ar << c;
return true;
}

long CImage_Archive::GetC()
{
unsigned char c;
ar >> c;
return c;
}

namespace stingray {
namespace foundation {

//////////////////////////////////////////////////////////////////////////

SECImage::SECImage(): m_pImage(0)
{
m_pPalette = NULL;
m_lpBMI = 0;
m_lpSrcBits = 0;
}

SECImage::~SECImage()
{
delete m_pImage;
delete m_pPalette;
}

#ifdef _DEBUG
void SECImage::AssertValid() const
{
ASSERT(m_pImage != 0);
}
void SECImage::Dump(CDumpContext& dc) const
{
CObject::Dump(dc);
}
#endif

DWORD SECImage::dwGetWidth() const
{
return m_pImage->GetWidth();
}

DWORD SECImage::dwGetHeight() const
{
return m_pImage->GetHeight();
}

BOOL SECImage::CopyImage(SECImage* pSrc)
{
m_pImage->Copy(*pSrc->m_pImage);
if (!CreatePalette())
return FALSE;
m_lpSrcBits = m_pImage->GetBits();
m_lpBMI = (LPBITMAPINFO) m_pImage->GetDIB();
return TRUE;
}

BOOL SECImage::ConvertImage(SECImage* pSrc)
{
m_pImage->Transfer(*pSrc->m_pImage);
return TRUE;
}

CBitmap* SECImage::MakeBitmap(CDC* pDC, const TCHAR* lpszFileName)
{
if (!LoadImage(lpszFileName))
return NULL;
return MakeBitmap(pDC);
}

CBitmap* SECImage::MakeBitmap(CDC* pDC)
{
HBITMAP bm = m_pImage->MakeBitmap(*pDC);
if (bm == NULL)
return NULL;
return CBitmap::FromHandle(bm);
}

CPalette* SECImage::GetPalette()
{
return m_pPalette;
}

BOOL SECImage::PreLoadImage()
{
return TRUE;
}

BOOL SECImage::PostLoadImage()
{
if (!CreatePalette())
return FALSE;
m_lpSrcBits = m_pImage->GetBits();
m_lpBMI = (LPBITMAPINFO) m_pImage->GetDIB();
return TRUE;
}

BOOL SECImage::LoadImage(CFile* pFile)
{
if (!PreLoadImage())
return FALSE;

if (!DoLoadImage(pFile))
return FALSE;

if (!PostLoadImage())
return FALSE;

return TRUE;
}

BOOL SECImage::LoadImage(LPCTSTR lpszFileName)
{
CFile file;

if (!file.Open(lpszFileName, CFile::modeRead))
return FALSE;

return LoadImage(&file);
}

BOOL SECImage::PreSaveImage()
{
return TRUE;
}

BOOL SECImage::PostSaveImage()
{
return TRUE;
}

BOOL SECImage::SaveImage(CFile* pFile)
{
if (!PreSaveImage())
return FALSE;

if (!DoSaveImage(pFile))
return FALSE;

if (!PostSaveImage())
return FALSE;

return TRUE;
}

BOOL SECImage::SaveImage(LPCTSTR lpszFileName)
{
CFile file;
if (!file.Open(lpszFileName, CFile::modeWrite))
return FALSE;
return SaveImage(&file);
}

BOOL SECImage::DoLoadImage(CFile* pFile)
{
return FALSE;
}

BOOL SECImage::DoSaveImage(CFile* pFile)
{
return FALSE;
}

BOOL SECImage::CreatePalette()
{
BITMAPINFO* pBMI = (LPBITMAPINFO) m_pImage->GetDIB();
DWORD dwColors = 0;
if (pBMI->bmiHeader.biClrUsed)
{
dwColors = pBMI->bmiHeader.biClrUsed;
}
else
{
switch(pBMI->bmiHeader.biBitCount)
{
case 1:
dwColors = 2;
break;
case 4 :
dwColors = 16;
break;
case 8 :
dwColors = 256;
break;
default :
dwColors = 0;
}
}

// If 24 bpp, then all color information is stored with image data
int nSrcBitsPerPixel = pBMI->bmiHeader.biBitCount;
if (nSrcBitsPerPixel == 24)
return TRUE;

// Create a LOGPALETTE structure and convert the colormap entries
// to this format. LOGPALETTE is then used for palette creation.
LPLOGPALETTE pPal = (LPLOGPALETTE) malloc(sizeof(LOGPALETTE) + dwColors * sizeof(PALETTEENTRY));

if (!pPal)
{
TRACE(_T("SECImage::CreatePalette failed allocation of %d colors\n"), dwColors);
return FALSE;
}

pPal->palVersion = 0x300;
pPal->palNumEntries = (WORD) dwColors;
RGBQUAD *pRGB = m_pImage->GetPalette();
for (DWORD dw=0; dw < dwColors; dw++)
{
pPal->palPalEntry[dw].peRed = pRGB[dw].rgbRed;
pPal->palPalEntry[dw].peGreen = pRGB[dw].rgbGreen;
pPal->palPalEntry[dw].peBlue = pRGB[dw].rgbBlue;
pPal->palPalEntry[dw].peFlags = 0;
}

// delete any existing palette
if (m_pPalette)
{
m_pPalette->DeleteObject();
delete m_pPalette;
m_pPalette = NULL;
}

// create away...
m_pPalette = new CPalette;
BOOL bResult = m_pPalette->CreatePalette(pPal);
if (pPal)
free(pPal);
return bResult;
}

BOOL SECImage::FlipHorz()
{
return m_pImage->Mirror();
}

BOOL SECImage::FlipVert()
{
return m_pImage->Flip();
}

BOOL SECImage::Rotate90(BOOL bClockwise)
{
return bClockwise? m_pImage->RotateLeft(): m_pImage->RotateRight();
}

void SECImage::ContrastImage(short nSharpen)
{
m_pImage->Light(0, nSharpen);
}

BOOL SECImage::Crop(long nLeft, long nTop, long nWidth, long nHeight)
{
return m_pImage->Crop(nLeft, nTop, nLeft+nWidth, nTop-nHeight);
}

DWORD SECImage::NumBytes() const
{
return m_pImage->GetSize();
}

WORD SECImage::NumColors() const
{
return (WORD) m_pImage->GetNumColors();
}

int SECImage::StretchDIBits(CDC* pDC, int XDest, int YDest, int cxDest, \
int cyDest, int XSrc, int YSrc, int cxSrc, int cySrc, const void* lpBits, \
LPBITMAPINFO lpbmi, UINT fuColorUse, DWORD fdwRop)
{
CRect rc(XSrc, YSrc, XSrc+cxSrc, YSrc+cySrc);
return m_pImage->Draw(*pDC, XDest, YDest, cxDest, cyDest);
}

BOOL SECImage::CreateFromBitmap(CDC* pDC, CBitmap* pSrcBitmap)
{
BITMAP bm;
// get informations about the bitmap
pSrcBitmap->GetObject(sizeof(BITMAP), (LPSTR) &bm);
// create the image
m_pImage->Create(bm.bmWidth, bm.bmHeight, bm.bmBitsPixel, 0);
// create a device context for the bitmap

// copy the pixels
if (GetDIBits(*pDC, *pSrcBitmap, 0, m_pImage->GetHeight(), m_pImage->GetBits(), \
(LPBITMAPINFO) m_pImage->GetDIB(), DIB_RGB_COLORS) == 0)
{
TRACE(_T("GetDIBits failed"));
return FALSE;
}

if (!CreatePalette())
{
return FALSE;
}
m_lpSrcBits = m_pImage->GetBits();
m_lpBMI = (LPBITMAPINFO) m_pImage->GetDIB();
return TRUE;
}

void SECImage::Serialize(CArchive& ar)
{
CObject::Serialize(ar);

CImage_Archive f(ar);
if (ar.IsStoring())
{
m_pImage->Encode(&f, CXIMAGE_FORMAT_BMP);
}
else
{
m_pImage->Decode(&f, CXIMAGE_FORMAT_BMP);
PostLoadImage();
}
}

//////////////////////////////////////////////////////////////////////////

IMPLEMENT_SERIAL(SECDib, CObject, 1)

SECDib::SECDib()
{
m_pImage = new CxImageBMP;
}

SECDib::~SECDib()
{
}

BOOL SECDib::DoLoadImage(CFile* pFile)
{
CImage_File file(pFile);
CxImageBMP* pImage = (CxImageBMP*) m_pImage;
return pImage->Decode(&file);
}

BOOL SECDib::DoSaveImage(CFile* pFile)
{
CImage_File file(pFile);
CxImageBMP* pImage = (CxImageBMP*) m_pImage;
return pImage->Encode(&file);
}

void SECDib::Serialize(CArchive& ar)
{
SECImage::Serialize(ar);
}

#ifdef _DEBUG
void SECDib::AssertValid() const
{
SECImage::AssertValid();
}
void SECDib::Dump(CDumpContext& dc) const
{
SECImage::Dump(dc);
}
#endif

//////////////////////////////////////////////////////////////////////////

IMPLEMENT_SERIAL(SECJpeg, CObject, 1)

SECJpeg::SECJpeg()
{
m_bQuantize = FALSE;
m_nQuality = 75;
m_nSmoothing = 0;
m_bOptimizeEntropyCoding = FALSE;
m_bArithmeticCoding = FALSE;
m_pImage = new CxImageJPG;
}

SECJpeg::~SECJpeg()
{
}

BOOL SECJpeg::DoLoadImage(CFile* pFile)
{
CImage_File file(pFile);
CxImageJPG *pImage = (CxImageJPG*) m_pImage;
DWORD dwOption = 0;
if (m_bQuantize)
{
dwOption |= CxImageJPG::DECODE_QUANTIZE;
pImage->m_nQuantize = 256;
}
return pImage->Decode(&file);
}

BOOL SECJpeg::DoSaveImage(CFile* pFile)
{
CImage_File file(pFile);
CxImageJPG *pImage = (CxImageJPG*) m_pImage;
DWORD dwOption = 0;
if (m_bArithmeticCoding)
dwOption |= CxImageJPG::ENCODE_ARITHMETIC;
if (m_bOptimizeEntropyCoding)
dwOption |= CxImageJPG::ENCODE_OPTIMIZE;
if (m_nSmoothing != 0)
{
dwOption |= CxImageJPG::ENCODE_SMOOTHING;
pImage->m_nSmoothing = m_nSmoothing;
}
pImage->SetEncodeOption(dwOption);
pImage->SetJpegQuality((BYTE) m_nQuality);
return pImage->Encode(&file);
}

void SECJpeg::Serialize(CArchive& ar)
{
SECImage::Serialize(ar);
}

#ifdef _DEBUG
void SECJpeg::AssertValid() const
{
SECImage::AssertValid();
}
void SECJpeg::Dump(CDumpContext& dc) const
{
SECImage::Dump(dc);
}
#endif

} // namespace stingray::foundation
} // namespace stingray

//////////////////////////////////////////////////////////////////////////

IMPLEMENT_SERIAL(SECGif, CObject, 1)

SECGif::SECGif()
{
m_pImage = new CxImageGIF;
}

SECGif::~SECGif()
{
}

BOOL SECGif::DoLoadImage(CFile* pFile)
{
CImage_File file(pFile);
CxImageGIF* pImage = (CxImageGIF*) m_pImage;
return pImage->Decode(&file);
}

BOOL SECGif::DoSaveImage(CFile* pFile)
{
CImage_File file(pFile);
CxImageGIF* pImage = (CxImageGIF*) m_pImage;
return pImage->Encode(&file);
}

void SECGif::Serialize(CArchive& ar)
{
SECImage::Serialize(ar);
}

#ifdef _DEBUG
void SECGif::AssertValid() const
{
SECImage::AssertValid();
}
void SECGif::Dump(CDumpContext& dc) const
{
SECImage::Dump(dc);
}
#endif

void SECGif::SetTransparent(BOOL bArg)
{
m_pImage->SetTransIndex(bArg? 0: -1);
}

BOOL SECGif::GetTransparent()
{
return m_pImage->IsTransparent();
}

void SECGif::SetTransparentColors(BYTE cRed, BYTE cGreen, BYTE cBlue)
{
RGBQUAD s;
s.rgbRed = cRed;
s.rgbGreen = cGreen;
s.rgbBlue = cBlue;
m_pImage->SetTransColor(s);
}

COLORREF SECGif::GetTransparentColor()
{
RGBQUAD s = m_pImage->GetTransColor();
return RGB(s.rgbRed, s.rgbGreen, s.rgbBlue);
}

void SECGif::SetInterlace(BOOL bArg)
{
}

BOOL SECGif::GetInterlaced()
{
class Private: public CxImageGIF
{
public:
bool IsInterlaced() const { return (interlaced != 0); }
};

Private* pImage = (Private*) m_pImage;
return pImage->IsInterlaced();
}

//////////////////////////////////////////////////////////////////////////

IMPLEMENT_SERIAL(SECPcx, CObject, 1)

SECPcx::SECPcx()
{
m_pImage = new CxImagePCX;
}

SECPcx::~SECPcx()
{
}

BOOL SECPcx::DoLoadImage(CFile* pFile)
{
CImage_File file(pFile);
CxImagePCX* pImage = (CxImagePCX*) m_pImage;
return pImage->Decode(&file);
}

BOOL SECPcx::DoSaveImage(CFile* pFile)
{
CImage_File file(pFile);
CxImagePCX* pImage = (CxImagePCX*) m_pImage;
return pImage->Encode(&file);
}

void SECPcx::Serialize(CArchive& ar)
{
SECImage::Serialize(ar);
}

#ifdef _DEBUG
void SECPcx::AssertValid() const
{
SECImage::AssertValid();
}
void SECPcx::Dump(CDumpContext& dc) const
{
SECImage::Dump(dc);
}
#endif

//////////////////////////////////////////////////////////////////////////

IMPLEMENT_SERIAL(SECTarga, CObject, 1)

SECTarga::SECTarga()
{
m_pImage = new CxImageTGA;
}

SECTarga::~SECTarga()
{
}

BOOL SECTarga::DoLoadImage(CFile* pFile)
{
CImage_File file(pFile);
CxImageTGA* pImage = (CxImageTGA*) m_pImage;
return pImage->Decode(&file);
}

BOOL SECTarga::DoSaveImage(CFile* pFile)
{
CImage_File file(pFile);
CxImageTGA* pImage = (CxImageTGA*) m_pImage;
return pImage->Encode(&file);
}

void SECTarga::Serialize(CArchive& ar)
{
SECImage::Serialize(ar);
}

#ifdef _DEBUG
void SECTarga::AssertValid() const
{
SECImage::AssertValid();
}
void SECTarga::Dump(CDumpContext& dc) const
{
SECImage::Dump(dc);
}
#endif

//////////////////////////////////////////////////////////////////////////

IMPLEMENT_SERIAL(SECTiff, CObject, 1)

SECTiff::SECTiff()
{
m_pImage = new CxImageTIF;
}

SECTiff::~SECTiff()
{
}

BOOL SECTiff::DoLoadImage(CFile* pFile)
{
CImage_File file(pFile);
CxImageTIF* pImage = (CxImageTIF*) m_pImage;
return pImage->Decode(&file);
}

BOOL SECTiff::DoSaveImage(CFile* pFile)
{
CImage_File file(pFile);
CxImageTIF* pImage = (CxImageTIF*) m_pImage;
return pImage->Encode(&file);
}

void SECTiff::Serialize(CArchive& ar)
{
SECImage::Serialize(ar);
}

#ifdef _DEBUG
void SECTiff::AssertValid() const
{
SECImage::AssertValid();
}
void SECTiff::Dump(CDumpContext& dc) const
{
SECImage::Dump(dc);
}
#endif

//////////////////////////////////////////////////////////////////////////

namespace stingray {
namespace foundation {

// Standard file extensions for the supported formats.
// Logic that uses this array assumes the file extension size to be always 3, if you
// make an entry that conflicts with this assumption change the logic in ParseImage.
// Modify GetImage below when you modify this array.

LPCTSTR strFileExtns[] =
{
_T(".dib"),
_T(".gif"),
_T(".pcx"),
_T(".tif"),
_T(".tgs"),
_T(".bmp"),
_T(".jpg")
};

// Maps an index in the strFileExtns array into an SECImage object and returns it.
static SECImage* GetImage(UINT nImage)
{
switch(nImage)
{
case 0: return new SECDib();
case 1: return new SECGif();
case 2: return new SECPcx();
case 3: return new SECTiff();
case 4: return new SECTarga();
case 5: return new SECDib();
case 6: return new SECJpeg();
default:
// Either nImage is out of bounds of strFileExtns or the corresponding
// image format was not included in the build config.
return NULL;
}
}

SECImage* SECImage::ParseImage(LPCTSTR lpszPathName)
{
UINT nKnownExtns = (sizeof(strFileExtns) / sizeof(strFileExtns[0]));
// First see if the file extension matches any of our pre-defined extensions.
for(UINT n = 0; n < nKnownExtns; n++)
{
// see if extension matches
ASSERT(strFileExtns[n][0] == '.');
LPCTSTR lpszDot = _tcsrchr(lpszPathName, '.');
if (lpszDot != NULL && lstrcmpi(lpszDot, strFileExtns[n]) == 0)
{
// File extension matches
SECImage* pImage = GetImage(n);
if(pImage == NULL) break; // Possible if the corresponding image
// format was not selected in the build config.
if(pImage->LoadImage(lpszPathName))
return pImage; // Succesfully loaded!
// LoadImage failed.
delete pImage;
break; // File extension is not helping!
}
}

// File extension did not help,
// Let's try calling LoadImage with all known formats
CFile file;
TRY
{
if(!file.Open(lpszPathName, CFile::modeRead))
return NULL;
}
CATCH( CFileException, e )
{
TRACE1("File could not be opened %s \n", e->m_cause);
return NULL;
}
END_CATCH
SECImage* pResultImage = ParseImage(&file);
file.Close();
return pResultImage;
}

SECImage* SECImage::ParseImage(CFile* pFile)
{
UINT nKnownExtns = (sizeof(strFileExtns) / sizeof(strFileExtns[0]));
for(UINT n = 0; n < nKnownExtns; n++)
{
SECImage* pImage = GetImage(n);
if(pImage == NULL) continue; // Possible if the corresponding image
// format was not selected in the build config.

CFile* dup = pFile->Duplicate();
if(pImage->LoadImage(dup))
return pImage; // Succesfully loaded!
// LoadImage failed.
delete pImage;
delete dup;
}
// Doesn't match any of the known formats, just return NULL
return NULL;
}

} // namespace stingray::foundation
} // namespace stingray

#endif

GeneralRe: interface with Rogue Wave Stingray Studio Pin
Davide Pizzolato15-Jan-04 9:37
Davide Pizzolato15-Jan-04 9:37 
GeneralRe: interface with Rogue Wave Stingray Studio Pin
alexander chupeev16-Jan-04 3:09
alexander chupeev16-Jan-04 3:09 
QuestionHow to use without MFC Pin
b100dian14-Jan-04 9:48
b100dian14-Jan-04 9:48 
AnswerRe: How to use without MFC Pin
Davide Pizzolato14-Jan-04 10:16
Davide Pizzolato14-Jan-04 10:16 
GeneralRe: How to use without MFC Pin
b100dian14-Jan-04 11:01
b100dian14-Jan-04 11:01 
GeneralWrite text on a TIFF Pin
jsanjosembet.es14-Jan-04 2:54
jsanjosembet.es14-Jan-04 2:54 
GeneralRe: Write text on a TIFF Pin
Davide Pizzolato14-Jan-04 6:56
Davide Pizzolato14-Jan-04 6:56 
GeneralRe: Write text on a TIFF Pin
jsanjosembet.es14-Jan-04 20:57
jsanjosembet.es14-Jan-04 20:57 
GeneralAccess violation if I try TIFF *tif = TIFFOpen( Pin
Trifon13-Jan-04 3:06
Trifon13-Jan-04 3:06 
GeneralRe: Access violation if I try TIFF *tif = TIFFOpen( Pin
Davide Pizzolato14-Jan-04 1:30
Davide Pizzolato14-Jan-04 1:30 
GeneralRe: Access violation if I try TIFF *tif = TIFFOpen( Pin
Trifon14-Jan-04 2:08
Trifon14-Jan-04 2:08 
GeneralRe: Access violation if I try TIFF *tif = TIFFOpen( Pin
Davide Pizzolato14-Jan-04 7:09
Davide Pizzolato14-Jan-04 7:09 
Generalreg CxImageTIF Pin
evangedhivya8-Jan-04 20:00
evangedhivya8-Jan-04 20:00 
GeneralRe: reg CxImageTIF Pin
Davide Pizzolato9-Jan-04 2:12
Davide Pizzolato9-Jan-04 2:12 
Generalreg tiff files Pin
evangedhivya8-Jan-04 19:58
evangedhivya8-Jan-04 19:58 
Generalreg tiff files Pin
evangedhivya8-Jan-04 17:31
evangedhivya8-Jan-04 17:31 
GeneralRe: reg tiff files Pin
Davide Pizzolato8-Jan-04 19:42
Davide Pizzolato8-Jan-04 19:42 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.