Click here to Skip to main content
15,888,968 members
Articles / Programming Languages / C++
Article

Image Compressor

Rate me:
Please Sign up or sign in to vote.
2.79/5 (14 votes)
18 Jun 2009CPOL3 min read 45.8K   4K   17   11
Compressing Images the easiest way
ImageCompressor_source

Introduction

It is very often that one needs to send pictures by email. Because of the size of the image files it takes very long to upload these images, especially if one has a slow internet connection. I have been using MS Paint to open the files and used its Save As function to save the image files in JPEG format. The problem was the time it takes to open each file, Save As, and enter file name. This little program addresses this problem in that it uses MFC built in classes plus the very reliable CxImage class to perform compression. The user just needs to add the source folder and destination folder and all the image files are loaded and saved without any other user input.

Background

The conversion all takes place using the CxImage class. The class is available both in a lite version and the complete one. The CodeProject site also has detailed article on how to use the CxImage class. It's not really required but it would give you some idea of what actually is going on.

Using the Code

It’s a very simple dialog based application. The source directory is selected by the user and then the destination directory is selected by the user. The files are read from the source directory and then converted in a while loop. The files which are to be converted have to be of the extension JPEG, BMP, JPG, or TIFF (this all is done via if statements). A progress control bar is added and based on the number of files converted it progresses file by file. The files that are successfully converted are displayed in a window, while all the files which are not converted are marked as errors and then displayed in the second window. A slider control selects the ratio of compression to achieve. All the conversion takes place with the help of the CxImage class which loads the image, sets the JPEG quality and then saves the file in the directory selected by the user. Two Listboxes are also added with one displaying the result of the files successfully converted and the later filenames which have not been converted.

The source and destination directories are selected using BROWSEINFO structure as:

C++
BROWSEINFO bi = { 0 };
bi.lpszTitle = _T("Select path for Source Directory");
bi.ulFlags = BIF_USENEWUI;
LPITEMIDLIST pidl = SHBrowseForFolder ( &bi );
if ( pidl != 0 )
{
    // get the name of the folder
    TCHAR path[MAX_PATH];
    if ( SHGetPathFromIDList ( pidl, path ) )
    {
        _tprintf ( _T("Selected Folder: %s\n"), path );
    }
    m_SourceDir = path;
    UpdateData(FALSE);

    // free memory used
    IMalloc * imalloc = 0;
    if ( SUCCEEDED( SHGetMalloc ( &imalloc )) )
    {
        imalloc->Free ( pidl );
        imalloc->Release ( );
    }

On clicking the Start Button the number of files to be converted are first calculated and based on the number of files calculated, and file names are generated using the code. The file names generated are stored in a CStringArray object.

C++
CString numb;
CStringArray filenames;
CString add = "\\image";
CString add1 = ".jpg";
for (int x=1;x<=n;x++)
{
    numb.Format("%d",x);
    CString fname = m_DestDir+add+numb+add1;
    filenames.Add(fname);
}

Using a CFileFind class object the directory selected as source directory is then used in a while loop to iterate through each file and based on the filenames already generated, file names are given. The progress bar moves file by file and eventually any error generated is listed in the list box alongside the file names successfully converted.

C++
int no = filenames.GetCount();      // getting total number of file names from CStringArray object
CString filename;                   // making sure a valid file extension is selected
m_ProgressBar.SetRange(0,n);
m_ProgressBar.SetStep(1);
BOOL bS1 = finder.FindFile(_T(m_SourceDir+CString("\\*.*")));
int num=0;
m_Slider = m_SliderValue.GetPos();
while(bS1)
{
    bS1 = finder.FindNextFile();
    if(finder.IsDots() || finder.IsDirectory())
        continue;
    filename = finder.GetFileTitle();   // getting the filename used in the following if statement
    if(num==no)                         // if true we have converted all the files
        break;      
    if ((filename+CString(".jpg") == finder.GetFileName()) || 
        (filename+CString(".bmp") == finder.GetFileName()) ||
        (filename+CString(".jpeg") == finder.GetFileName()) || 
        (filename+CString(".tiff") == finder.GetFileName()))
    {                 
        image.Load(finder.GetFilePath(),0); // loading file into memory using CxImage Class
        image.SetJpegQuality(m_Slider);           // setting the compression ratio
        image.Save(filenames.GetAt(num),CXIMAGE_FORMAT_JPG);  // saving the file using
                                                              // already generated filename
        m_ConvFiles.AddString(filename+CString(" -->> Converted successfully"));
        m_ProgressBar.StepIt();
        ++num;
    }
    else
    {
        m_Errors.AddString(finder.GetFileName()+CString(" -->> File format Invalid"));
        continue;
    }
}

Points of Interest

The application uses CxImage class for achievement the desired compression.

History

Version 1.0.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


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

Comments and Discussions

 
GeneralMy vote of 1 Pin
Tomas Rapkauskas2-Jul-09 4:24
Tomas Rapkauskas2-Jul-09 4:24 
GeneralMy vote of 2 Pin
Niklas L28-Jun-09 23:05
Niklas L28-Jun-09 23:05 
GeneralMy vote of 1 Pin
Joe Woodbury28-Jun-09 10:06
professionalJoe Woodbury28-Jun-09 10:06 
Your code has several problems.

1) You turned off precompiled headers.

2) In your linker settings, you hard code paths to each library instead of using the "Additional Library Directory" setting.

3) In CImageCompressorApp::InitInstance() you didn't change the registry key.

4) You don't use the registry to store the last settings.

5) You repeat the code for OnBnClickedBrowse1 and OnBnClickedBrowse2, instead of making a common routine which returns a CString.

5) You don't ensure the directories exist.

6) If I enter the source path manually and then hit tab, you erase what was entered.

6) You allow the Start button to be clicked even fields contain invalid data

6) You do two scans of the source directory. Moreover, you make a massive assumption that the files between the first and second scan won't change. Why not simply scan and do the operations once?

7) OnBnClickedStart() causes the dialog to become unresponsive. Not only can you not cancel the operation, the progress bar will never update.

8) You separate errors from progress. Why not list each file and then whether it worked or failed and if failed, what the error was?
GeneralNewbee problem i guess so Pin
Muhammad Hassan Haider28-Jun-09 11:57
Muhammad Hassan Haider28-Jun-09 11:57 
GeneralRe: Newbee problem i guess so Pin
Joe Woodbury28-Jun-09 17:39
professionalJoe Woodbury28-Jun-09 17:39 
GeneralRe: Newbee problem i guess so Pin
Muhammad Hassan Haider2-Jul-09 7:26
Muhammad Hassan Haider2-Jul-09 7:26 
GeneralMy vote of 1 Pin
f224-Jun-09 7:50
f224-Jun-09 7:50 
GeneralMy vote of 1 Pin
Gilad Novik22-Jun-09 11:34
Gilad Novik22-Jun-09 11:34 
AnswerRe: My vote of 1 Pin
Muhammad Hassan Haider22-Jun-09 12:39
Muhammad Hassan Haider22-Jun-09 12:39 
Questioncan you build this project in vs2005? Pin
xuplus18-Jun-09 14:21
xuplus18-Jun-09 14:21 
AnswerRe: can you build this project in vs2005? Pin
Muhammad Hassan Haider19-Jun-09 3:10
Muhammad Hassan Haider19-Jun-09 3:10 

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.