z Saving Pictures to JPG in VB
The new vbAccelerator Site - more VB and .NET Code and Controls
Source Code
4 vbMedia  

Saving Pictures to JPG Files from VB


 NOTE: this code has been superceded by the version at the new site.


Sample JPG Image

Download the SaveJPEG Project (including ijl11.dll) (150kb)

  UpdatedUpdated! 21 March 2000  
  Intel have now released version 1.1 of this library (ijl11.dll) so the sample has been updated to use this version. There are no functional changes in this version but it is supposedly quicker and includes some minor bug fixes.  
  Added LoadJPGFromPtr and SaveJPGToPtr. These methods allow you to load and save the JPEG to a byte array or memory block rather than Save to disk.  
  UpdatedUpdated! 15 August 1999  
  The last version of this code corrupted images when asked to load or save files which weren't an even multiple of 4 bytes across (the result was a diagonal distortion). This was because DIB files are padded to 4 byte (i.e. 32 bit) boundaries, but my interface to the JPG library assumed no alignment. I missed this because (get this !) I tested with only 8 images, and all of them were a multiple of 4 in width...

It is better now, and I also added some information about the Performance of this library.
  The Quality argument has been added to the SaveJPG method, allowing you to specify the quality/compression of the saved JPG image.  

Whilst Visual Basic provides support for loading graphic files in various formats into a StdPicture object, it sadly forgets about all of these when it comes to saving the file again. You normally only have one choice of file format for writing: a BMP at the system colour depth.

Whilst there are various third party controls available to save files in other formats, these are often have unacceptable 'per seat' licensing policies and can be incredibly expensive. This article shows how to use a free JPEG DLL library to save VB pictures.

JPEG File Format
The JPEG file format is aimed at providing very high compression levels for photographic quality images. Before deciding whether you want to use JPEG files in any application you write, there are points to consider about how JPEG operates.

  • High compression ratio
  • Wide support - thanks to the free availability of source code to implement JPG read and write, many applications support it. Windows 98 and 2000 even include native support for reading JPG files.
  • No license requirements, unlike GIF.
  • The JPEG format is lossy: colour accuracy is affected when you save the file. Images saved to JPEG many times loose quality in a similar way that multiple generations of analogue recordings do.
  • It is difficult to encode - not a task you would like to perform in VB code!
  • Works on true colour (24 bit images); not suitable as a format for storing files aimed at paletised systems.
The Independent JPEG Group have done a great deal to make the JPEG format much more accessible to developers by providing free, platform independent C source code to implement JPEG load and save functions. Their library is used in Internet Explorer *, Netscape * Navigator and countless other projects (some of which have even have the audacity to charge for free code!), including a JPEG Library DLL, ijl11.dll, available from the Intel* Developer Site.

This DLL makes conversion to and from JPG simpler by working on a DIB byte format. This makes it easier to use for Windows programmers than the Independent JPEG Group's C code, since the input and output format in memory is a standard Windows format. Conversion between VB StdPicture objects and a DIB is achieved using the cDIBSection Class.

From VB
Download the sample project. This contains all the files required. Firstly, unzip Ijl11.zip and place ijl11.dll in your system's path (ideally in the Windows\System directory). Read the licensing agreement included in the zip. If you are going to use this file for a distributed or commercial project you must download a registered copy (free) from Intel at their JPEG Library page. Then there are two VB files needed:
  • mIJL.bas
  • cDIBSection.cls
mIJL.bas contains the declares for ijl11.dll and four wrapper functions:
  • LoadJPG
  • LoadJPGFromPtr
  • SaveJPG
  • SaveJPGToPtr
All these function accept an instance of the cDIBSection Class. The standard versions of the functions accept a file name as an argument, while the Ptr versions accept a long value pointing to a memory buffer and a variable indicating the buffer size.

Although VB can already load a JPG, LoadJPG is provided as it gives a shortcut for loading a JPG file directly into a cDIBSection class without requiring a StdPicture object. LoadJPGFromPtr allows you to load a JPG directly from a byte array containing the JPG, a function which can't be otherwise be achieved easily in VB.

To save a StdPicture object directly, you need to do this:

Dim c As New cDibSection

   ' Convert Picture object to DIBSection:
   c.CreateFromPicture picThis.Picture
   ' Save it:
   SaveJPG c, sFileName

Saving and Loading From Memory Buffers
To Load a JPG from a memory buffer, first you create a byte array containing all the bytes in the JPG, or use the Shell's IMalloc implementation to allocate memory directly and have that contain the JPG bytes. Then you pass the pointer to the data and the size of the buffer into the LoadJPGFromPtr method. If you use a byte array, the pointer is obtained using VB's VarPtr function:

   ' Assuming the byte array is b():
   lPtr = VarPtr(b(0))

To save a JPG to a memory buffer directly, you need to create a byte array or allocate sufficient memory to hold the resultant JPG. Normally this means creating a larger buffer than the resulting JPG. Since JPG always compresses an image, the size is always going to be smaller than the size of an equivalent DIB buffer to hold the bytes. In the sample code I chose 1/4 of the bytes in the DIBSection (m_cDib.Height * m_cDib.BytesPerScanLine / 4). Then you pass a pointer to this buffer and its size to the SaveJPGFromPtr. The method modifies the size variable passed in to reflect the actual size of the JPG created which you can then use to trim down the buffer to size.

Interestingly, using cDIBSection with the Intel JPG library can be substantially faster than than using VB's standard methods. The following code was used for benchmarking. In the VB case, a new StdPicture object is created and loaded with a JPG file. For the IJL library, a new cDIBSection object is created and the same JPG file is loaded:

Private Sub cmdIJL_Click()
   Dim fT As Double
   Dim cD As New cDIBSection
   fT = Timer
   LoadJPG cD, App.Path & "\earth.jpg"
   Debug.Print "Time:", Timer - fT
End Sub

Private Sub cmdVB_Click()
   Dim fT As Double
   Dim picThis As New StdPicture
   fT = Timer
   Set picThis = LoadPicture(App.Path & "\earth.jpg")
   Debug.Print "Time:", Timer - fT
End Sub

The tested file, earth.jpg, was a 1022x747 pixel JPG, with a file size of 66kb. Performance on the test machine (Pentium II 266 with 256Mb memory) showed the IJL library version to be more than twice as quick as the VB version. Typically, VB turned in a load speed of around 1 second, whilst the IJL version achieved around 0.4s.

TopBack to top
BackBack to vbMedia Source Code Overview
Source Code - What We're About!Back to Source Code Overview


About  Contribute  Send Feedback  Privacy

Copyright © 1998-2000, Steve McMahon ( steve@vbaccelerator.com). All Rights Reserved.
Last updated: 21 March 2000

* All Trademarks acknowledged.