2006-09-18

HOWTO: CHANGE BITMAP RESOLUTION

The bitmap resolution can be also very easily changed with gdi+.

The sample below uses the new GdiPlus-X classes from VFPX projects that can be downloaded from here: http://www.codeplex.com/wiki/view.aspx?projectname=vfpx&title=gdiplusx

*!* HOW TO CHNGE THE BITMAP RESOLUTION
* the code loads an image, changes its resolution to 200x200
* and saves it again as a bmp
*
http://msdn2.microsoft.com/en-us/library/system.drawing.bitmap.setresolution.aspx

do locfile("System.app")

with _screen.system.drawing
   * load image to gdi+
   local loBmp as xfcBitmap
   loBmp = .Bitmap.New(getpict())

   * change Bitmap Resolution
   loBmp.SetResolution(200,200)

   * save the bitmap
   loBmp.Save("c:\newresolution.bmp", .imaging.imageformat.bmp)

endwith
return

2006-09-17

Using TIFFs with the new GDI+ classes - UPDATE

As a continuation of my article from may 2006 published in UTMAG, entitled "Multiframe images with Gdi+" i wrote a New article published in the september 2006 issue of utmag called "Using TIFFs with the New Gdi+ classes" showing how to manipulate TIFF images using the New gdiplus-x library from VFP-X project. It also shows how to create TIFFs using all Compressions supported.

But I left one point not very clear. This came to me after I saw a question from Jennifer Slusher in the universal thread forums (thread id #1153672), asking how to create multiPage TIFFs in Compression 4 (ccitt4). in that article, I showed how to create common Multiframe TIFFs and also how to create a single frame TIFF using Compression, but forgot to show or comment about creating Multiframe TIFFs with Compression.

Multiframe TIFFs with Compression

Gdi+ by default uses the 'lzw lossless' Compression whenever asked to save as TIFF. According to Wayne Fulton, from www.scantips.com, "lossless means there is no quality loss due to Compression. lossless guarantees that you can always read back exactly what you thought you saved, bit-for-bit identical, without data corruption". so, unless we specify, gdi+ will always use lzw Compression on TIFFs.

To create a Multiframe TIFF with Compression different from lzw, we need to send some additional Encoder Parameters to gdi+, even if the original picture is already a TIFF with another Compression. The methods "save" and "saveadd" permit us to send more than one Encoder Parameter at a time. Then, all we need to do is to create another Encoder object based on the guid for the Compression Parameter category, and set its EncoderValue to the desired Compression, eg Compressionccitt4.

The sample below will ask for any three images. To ensure that it will be able to save using Compression ccitt4, it will first convert all the selected images to monochrome. Then it will create a Multiframe TIFF image file containing all selected images in the Compression ccitt4.



** The following example loads three Bitmap objects
** converts all Bitmaps to monochrome to be compatible with rle, ccitt3/4 Compression
** the code saves all three images in a single, multiple-frame TIFF
** file, using Compression format CCITT4 
DO LOCFILE("System.app")

WITH _SCREEN.SYSTEM.Drawing
    LOCAL loBmp AS xfcBitmap
    LOCAL loMultif AS xfcBitmap
    LOCAL loPage2 AS xfcBitmap
    LOCAL loPage3 AS xfcBitmap
    LOCAL myEncoder AS xfcEncoder
    LOCAL myCompEncoder AS xfcEncoder
    LOCAL myEncoderParameter AS xfcEncoderParameter
    LOCAL myCompEncoderParameter AS xfcEncoderParameter
    LOCAL myEncoderParameters AS xfcEncoderParameters

    *!* create three Bitmap objects.
    *!* 1st we load the original Bitmap,
    *!* and then get its monochrome version
    m.loBmp    = .BITMAP.New(GETPICT())
    m.loMultif = m.loBmp.getMonochrome()
    m.loBmp    = .BITMAP.New(GETPICT())
    m.loPage2  = m.loBmp.getMonochrome()
    m.loBmp    = .BITMAP.New(GETPICT())
    m.loPage3  = m.loBmp.getMonochrome()

    *!* release the original Bitmap because we'll not use it any more
    m.loBmp = NULL

    *!* create Encoder object based on the guid for the saveflag Parameter category.
    m.myEncoder = .Imaging.Encoder.saveflag

    *!* create Encoder object based on the guid for the Compression Parameter category.
    m.mycompEncoder = .Imaging.Encoder.Compression

    && create an EncoderParameters object.
    && EncoderParameters object has an array of EncoderParameter objects
    && in this case, there'll be 2 EncoderParameter objects in the array.
    m.myEncoderParameters = .Imaging.EncoderParameters.New(2)

    *!* save the first Page (frame).
    m.myEncoderParameter = .Imaging.EncoderParameter.New(m.myEncoder, ;
          .Imaging.EncoderValue.Multiframe)
    m.mycompEncoderParameter = .Imaging.EncoderParameter.New(m.mycompEncoder, ;
          .Imaging.EncoderValue.Compressionccitt4)

    m.myEncoderParameters.PARAM[1] = m.myEncoderParameter
    m.myEncoderParameters.PARAM[2] = m.mycompEncoderParameter
    m.loMultif.SAVE("c:\NewMultiframeCompress.tif", ;
          .Imaging.imageformat.TIFF, m.myEncoderParameters)

    *!* save the second Page (frame).
    *!* this time we will only change the 1st Parameter to "framedimensionPage"
    *!* the 2nd Parameter that sets the Compression will remain the same
    m.myEncoderParameter = .Imaging.EncoderParameter.New(m.myEncoder, ;
          .Imaging.EncoderValue.framedimensionPage)
    m.myEncoderParameters.PARAM[1] = m.myEncoderParameter
    m.loMultif.saveadd(m.loPage2, m.myEncoderParameters)

    *!* save the third Page (frame).
    *!* this time we don't need to make any change to the Encoder paramenters
    *!* we'll keep using the same Parameters used when we added the 2nd frame
    m.loMultif.saveadd(m.loPage3, m.myEncoderParameters)

    *!* close the multiple-frame file.
    *!* this time we call the "flush" Parameter to close the file.
    *!* we don't need the 2nd Parameter any more, so change it to null
    m.myEncoderParameter = .Imaging.EncoderParameter.New(m.myEncoder, ;
          .Imaging.EncoderValue.FLUSH)
    m.myEncoderParameters.PARAM[1] = m.myEncoderParameter
    m.myEncoderParameters.PARAM[2] = NULL
    m.loMultif.saveadd(m.myEncoderParameters)
ENDWITH
RETURN



Notice that the object myEncoderParameters contains a property "params" that is an array of Parameters.


Other related links:
TIFF, tag image file format
A few scanning tips

 

 

2006-09-12

Helper code to create image on the fly for "Using the Alpha Channel in Visual Foxpro Images" from Bernard Bout

Here's another very simple code that attends Bernard Bout, creating an image on the fly, based on his post entitled "Using the alpha channel in visual foxpro images". Again in this sample, I'm using the new Gdiplus-X classes from VFPX project that can be downloaded from GitHub



* Helper code to create image on the fly for
* Bernard Bout "Using the alpha channel in VFP images"
* http://weblogs.foxite.com/bernardbout/archive/2006/09/11/2436.aspx
*    image dimensions 300 x 270 pixels
*    make all image totally transparent
*    draw a light yellow - rgb(254,254,228) rectangle
*         centered in the main image.
*    save as PNG, to preserve the transparencies
DO LOCFILE("System.app")

WITH _SCREEN.SYSTEM.Drawing
    * create an empty bitmap
    LOCAL loBitmap AS xfcBitmap
    m.loBitmap = .BITMAP.New(300,270)

    * initialize the graphics object
    LOCAL loGfx AS xfcGraphics
    m.loGfx = .Graphics.FromImage(m.loBitmap)

    * make all image transparent
    m.loGfx.CLEAR(.COLOR.FromARGB(0,0,0,0))

    * draw the yellow rectangle
    m.loGfx.FillRectangle(.SolidBrush.New(.COLOR.FromRGB(254,254,228)), 10,9,278,249)

    * save as png to keep transparencies
    m.loBitmap.SAVE("c:\bernardboutagain.png", .Imaging.ImageFormat.Png)
ENDWITH
RETURN