Welcome Guest! You need to login or register to make posts.

Notification

Icon
Error

Options
Go to last post Go to first unread
Fedor  
#1 Posted : Saturday, April 30, 2005 6:00:00 AM(UTC)
Fedor

Rank: Advanced Member

Groups: Member, Administration, Moderator
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.

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");
	}
}

Edited by moderator Monday, May 28, 2012 8:46:44 PM(UTC)  | Reason: Not specified

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.