Rank: Advanced Member
Groups: Guest
Joined: 7/28/2003(UTC) Posts: 1,660
Thanks: 5 times Was thanked: 76 time(s) in 74 post(s)
|
This code sample demonstrates how to create a palette which is built for several images.OverviewWhen 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. ResolutionMulti-frame GIF FilesIf 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 IdeaThe 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 SampleBelow 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");
}
}
Edited by moderator Monday, May 28, 2012 8:46:44 PM(UTC)
| Reason: Not specified |
Best regards, Fedor Skvortsov
|