Welcome Guest Search | Active Topics | Members

HOWTO: Create a Palette Optimized for Several Bitmaps Options
Fedor
Posted: Saturday, April 30, 2005 2:00:00 PM

Rank: Advanced Member
Groups: Administration , Member

Joined: 7/28/2003
Posts: 1,254
Points: -345
Location: WA, US
This code sample demonstrates how to create a palette which is built for several images.

Overview

When you reduce colors, you may need to build a palette which is optimized for a group of images. Graphics Mill for .NET enables you to build an optimized palette from the single bitmap, however if you want to to use it for multiple images (not a multi-frame GIF file), you need to perform some additional steps.

This topic describes how to use Graphics Mill for .NET to build a palette which is optimized for several images.

Resolution

Multi-frame GIF Files

If you create a multi-frame GIF file, the only thing you need to do is to enable GIF optimization setting the GifWriter.Optimized property to true. You can also adjust the creation of the global palette using the GifWriter.BasisOptimizationFrameCount property. This property defines the number of frames that should be taken into account when generating a palette. Due a GIF format specification, no image data may be written before the global palette is saved. Therefore, a frame cannot be written as soon as the GifWriter.AddFrame method is called. Instead, the frame is stored in memory before the global palette is generated and saved to memory. Frames will be saved to the file only when the writer is closed. Obviously, if too many frames are added, it will consume too much memory. To avoid this, this property is used to specify a threshold for the number of frames to build a global palette for.

Non-GIF Files: General Idea

The general idea is to create a single image which will contain all pixels from the images we are building a palette for. Since palette generating algorithm is not sensible to the order of pixels, we can insert these pixels in the way which is most convenient to us.

The simplest way to join several images is to create an empty bitmap which has a single scanline and a width of the scanline equals to the number of pixels in all images we are joining. After that we just iterate through scanlines of these images and copy them to this bitmap.

Finally, when we get such bitmap and generate an optimized palette for it, this palette can be used as an optimal palette for specified group of images.

Non-GIF Files: Code Sample

Below you will find a class CommonPaletteCreator as well as an example of its usage. Read the comments in the code for more details.

Code:
public class CommonPaletteCreator
{
      Aurigma.GraphicsMill.Bitmap[] bitmaps = null;

      public CommonPaletteCreator()
      {

      }

      //Import RtlMoveMemory function for copying memory in unmanaged heap
      [DllImport("kernel32", EntryPoint="RtlMoveMemory")]
      private static extern int CopyMemory(IntPtr lpvDest, IntPtr lpvSrc, int cbCopy);

      public Aurigma.GraphicsMill.Bitmap[] Bitmaps
      {
            set
            {
                  bitmaps = value;
            }
            get
            {
                  return bitmaps;
            }
      }

      public Aurigma.GraphicsMill.ColorPalette CreatePalette()
      {                  
            //All source bitmaps should have the same pixel format
            Aurigma.GraphicsMill.PixelFormat commonPixelFormat =
                  Aurigma.GraphicsMill.PixelFormat.Format24bppRgb; //Aurigma.GraphicsMill.PixelFormat.Format32bppArgb

            //Total pixel count in all bitmaps
            int totalPixelCount = 0;
            foreach (Aurigma.GraphicsMill.Bitmap bitmap in bitmaps)
            {
                  if (bitmap.PixelFormat != commonPixelFormat)
                  {
                        //instead of exception throwing, we can also convert bitmap to required pixel format
                        throw new Exception("Only 24 bpp pixel format is supported.");
                  }
                  totalPixelCount += bitmap.Width * bitmap.Height;
            }
                  
            //Create common bitmap with width equals totalPixelCount and height equals 1
            using (Aurigma.GraphicsMill.Bitmap commonBitmap = new Aurigma.GraphicsMill.Bitmap(totalPixelCount, 1, commonPixelFormat))
            {
                  int bytesPerPixel = commonBitmap.BitsPerPixel / 8;
      
                  Aurigma.GraphicsMill.BitmapData commonBitmapData = commonBitmap.LockBits();

                  //Get pointer in unmanaged heap for common bitmap raw data
                  IntPtr commonBitmapPtr = commonBitmapData.Scan0;

                  //Copy data of source images to common image
                  foreach (Aurigma.GraphicsMill.Bitmap bitmap in bitmaps)
                  {
                        Aurigma.GraphicsMill.BitmapData bitmapData = bitmap.LockBits();

                        //Get pointer in unmanaged heap for bitmap raw data
                        IntPtr bitmapPtr = bitmapData.Scan0;

                        //Copy raw data from bitmap to common bitmap
                        for (int i = 0; i < bitmap.Height ; i++)
                        {
                              //Data actaully are not marshalled here, as we work in unmanaged heap only
                              CopyMemory(commonBitmapPtr, bitmapPtr,
                                    bitmapData.Width * bytesPerPixel);

                              //Pointer incrementing
                              bitmapPtr = (IntPtr)((int)(bitmapPtr) + bitmapData.Stride);
                              commonBitmapPtr = (IntPtr)((int)(commonBitmapPtr) + bitmapData.Width * bytesPerPixel);
                        }

                        bitmap.UnlockBits(bitmapData);
                  }

                  commonBitmap.UnlockBits(commonBitmapData);

                  //Create common palette
                  return new Aurigma.GraphicsMill.ColorPalette(commonBitmap, false);
            }
      }
}

class CommonPaletteTest
{
      ///

      /// The main entry point for the application.
      ///
      [STAThread]
      static void Main(string[] args)
      {
            //Load images
            Aurigma.GraphicsMill.Bitmap bitmap1 =
                  new Aurigma.GraphicsMill.Bitmap(@"C:\Flower.jpg");
            Aurigma.GraphicsMill.Bitmap bitmap2 =
                  new Aurigma.GraphicsMill.Bitmap(@"C:\Mountain.jpg");
            Aurigma.GraphicsMill.Bitmap bitmap3 =
                  new Aurigma.GraphicsMill.Bitmap(@"C:\Parrot.jpg");
      
            //Create common palette creator
            CommonPaletteCreator paletteCreator = new CommonPaletteCreator();
            
            //Set bitmaps for which we need to create common palette
            paletteCreator.Bitmaps = new Aurigma.GraphicsMill.Bitmap[]{bitmap1, bitmap2, bitmap3};

            //Create common palette
            Aurigma.GraphicsMill.ColorPalette commonPalette = paletteCreator.CreatePalette();

            //Reduce colors using common palette
            bitmap1.ColorManagement.ConvertToIndexed(8, Aurigma.GraphicsMill.ColorPaletteType.Custom,
                  commonPalette);
            bitmap2.ColorManagement.ConvertToIndexed(8, Aurigma.GraphicsMill.ColorPaletteType.Custom,
                  commonPalette);
            bitmap3.ColorManagement.ConvertToIndexed(8, Aurigma.GraphicsMill.ColorPaletteType.Custom,
                  commonPalette);

            //Save results
            bitmap1.Save(@"C:\Flower.png");
            bitmap2.Save(@"C:\Mountain.png");
            bitmap3.Save(@"C:\Parrot.png");
      }
}


Best regards,
Fedor Skvortsov
Users browsing this topic
Guest


Forum Jump
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.

Main Forum RSS : RSS

YAFVision Theme Created by Jaben Cargman (Tiny Gecko)
Yet Another Forum.net version 1.9.1.6 running under Cuyahoga.
Copyright © 2003-2006 Yet Another Forum.net. All rights reserved.