412 lines
11 KiB
C#
412 lines
11 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Drawing;
|
|
using System.Windows.Forms;
|
|
using FreeImageAPI;
|
|
using FreeImageAPI.Metadata;
|
|
using FreeImageAPI.Plugins;
|
|
|
|
namespace Sample11
|
|
{
|
|
public partial class MainForm : Form
|
|
{
|
|
public MainForm()
|
|
{
|
|
InitializeComponent();
|
|
}
|
|
|
|
[STAThread]
|
|
static void Main()
|
|
{
|
|
// Capture messages generated by FreeImage
|
|
FreeImageEngine.Message += new OutputMessageFunction(FreeImageEngine_Message);
|
|
|
|
Application.EnableVisualStyles();
|
|
Application.SetCompatibleTextRenderingDefault(false);
|
|
Application.Run(new MainForm());
|
|
}
|
|
|
|
static void FreeImageEngine_Message(FREE_IMAGE_FORMAT fif, string message)
|
|
{
|
|
// Display the message
|
|
// FreeImage continues code executing when all
|
|
// addes subscribers of 'Message' finished returned.
|
|
MessageBox.Show(message, "FreeImage-Message", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
}
|
|
|
|
// The FreeImageBitmap this sample will work with.
|
|
FreeImageBitmap bitmap = null;
|
|
|
|
// Replaces the current bitmap with the given one.
|
|
private void ReplaceBitmap(FreeImageBitmap newBitmap)
|
|
{
|
|
// Checks whether the bitmap is usable
|
|
if (newBitmap == null || newBitmap.IsDisposed)
|
|
{
|
|
MessageBox.Show(
|
|
"Unexpected error.",
|
|
"Error",
|
|
MessageBoxButtons.OK,
|
|
MessageBoxIcon.Error);
|
|
}
|
|
|
|
// Check whether the image type of the new bitmap is 'FIT_BITMAP'.
|
|
// If not convert to 'FIT_BITMAP'.
|
|
if (newBitmap.ImageType != FREE_IMAGE_TYPE.FIT_BITMAP)
|
|
{
|
|
if (!newBitmap.ConvertType(FREE_IMAGE_TYPE.FIT_BITMAP, true))
|
|
{
|
|
MessageBox.Show(
|
|
"Error converting bitmap to standard type.",
|
|
"Error",
|
|
MessageBoxButtons.OK,
|
|
MessageBoxIcon.Error);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Dispose the old bitmap only in case it exists and
|
|
// the old instance is another than the new one.
|
|
if ((bitmap != null) && !object.ReferenceEquals(bitmap, newBitmap))
|
|
{
|
|
bitmap.Dispose();
|
|
}
|
|
// Dispose the picturebox's bitmap in case it exists.
|
|
if (pictureBox.Image != null)
|
|
{
|
|
pictureBox.Image.Dispose();
|
|
}
|
|
|
|
// Set the new bitmap.
|
|
pictureBox.Image = (Bitmap)(bitmap = newBitmap);
|
|
|
|
// Update gui.
|
|
UpdateBitmapInformations();
|
|
UpdateFrameSelection();
|
|
}
|
|
|
|
// Get bitmap properties and display them in the gui.
|
|
private void UpdateBitmapInformations()
|
|
{
|
|
if (Bitmap)
|
|
{
|
|
// Get width
|
|
lWidth.Text = String.Format("Width: {0}", bitmap.Width);
|
|
// Get Height
|
|
lHeight.Text = String.Format("Height: {0}", bitmap.Height);
|
|
// Get color depth
|
|
lBpp.Text = String.Format("Bpp: {0}", bitmap.ColorDepth);
|
|
// Get number of metadata
|
|
ImageMetadata mData = bitmap.Metadata;
|
|
mData.HideEmptyModels = true;
|
|
int mCnt = 0;
|
|
foreach (MetadataModel model in mData.List)
|
|
{
|
|
mCnt += model.Count;
|
|
}
|
|
lMetadataCount.Text = String.Format("Metadata: {0}", mCnt);
|
|
// Get image comment
|
|
lComment.Text = String.Format("Image-comment: {0}", bitmap.Comment != null ? bitmap.Comment : String.Empty);
|
|
// Get the number of real colors in the image
|
|
lColors.Text = String.Format("Colors: {0}", bitmap.UniqueColors);
|
|
}
|
|
else
|
|
{
|
|
// Reset all values
|
|
lWidth.Text = String.Format("Width: {0}", 0);
|
|
lHeight.Text = String.Format("Height: {0}", 0);
|
|
lBpp.Text = String.Format("Bpp: {0}", 0);
|
|
lMetadataCount.Text = String.Format("Metadata: {0}", 0);
|
|
lComment.Text = String.Format("Image-comment: {0}", String.Empty);
|
|
lColors.Text = String.Format("Colors: {0}", 0);
|
|
}
|
|
}
|
|
|
|
// Update combobox for frame selection.
|
|
private void UpdateFrameSelection()
|
|
{
|
|
cbSelectFrame.Items.Clear();
|
|
if (Bitmap)
|
|
{
|
|
// Get number of frames in the bitmap
|
|
if (bitmap.FrameCount > 1)
|
|
{
|
|
// Add an entry for each frame to the combobox
|
|
for (int i = 0; i < bitmap.FrameCount; i++)
|
|
{
|
|
cbSelectFrame.Items.Add(String.Format("Frame {0}", i + 1));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Returns true in case the variable 'bitmap'
|
|
// is set and not disposed.
|
|
private bool Bitmap
|
|
{
|
|
get { return ((bitmap != null) && (!bitmap.IsDisposed)); }
|
|
}
|
|
|
|
private void bLoadImage_Click(object sender, EventArgs e)
|
|
{
|
|
if (ofd.ShowDialog() == DialogResult.OK)
|
|
{
|
|
try
|
|
{
|
|
// Load the file using autodetection
|
|
FreeImageBitmap fib = new FreeImageBitmap(ofd.FileName);
|
|
// Rescale the image so that it fits the picturebox
|
|
// Get the plugin that was used to load the bitmap
|
|
FreeImagePlugin plug = PluginRepository.Plugin(fib.ImageFormat);
|
|
lImageFormat.Text = String.Format("Image-format: {0}", plug.Format);
|
|
// Replace the existing bitmap with the new one
|
|
ReplaceBitmap(fib);
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
}
|
|
|
|
private void bSaveImage_Click(object sender, EventArgs e)
|
|
{
|
|
if (pictureBox.Image != null)
|
|
{
|
|
try
|
|
{
|
|
if (sfd.ShowDialog() == DialogResult.OK)
|
|
{
|
|
// Save the bitmap using autodetection
|
|
using (FreeImageBitmap temp = new FreeImageBitmap(pictureBox.Image))
|
|
{
|
|
temp.Save(sfd.FileName);
|
|
}
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
}
|
|
|
|
private void bRotate_Click(object sender, EventArgs e)
|
|
{
|
|
if (Bitmap)
|
|
{
|
|
// Create a temporary rescaled bitmap
|
|
using (FreeImageBitmap temp = bitmap.GetScaledInstance(
|
|
pictureBox.DisplayRectangle.Width, pictureBox.DisplayRectangle.Height,
|
|
FREE_IMAGE_FILTER.FILTER_CATMULLROM))
|
|
{
|
|
if (temp != null)
|
|
{
|
|
// Rotate the bitmap
|
|
temp.Rotate((double)vRotate.Value);
|
|
if (pictureBox.Image != null)
|
|
{
|
|
pictureBox.Image.Dispose();
|
|
}
|
|
// Display the result
|
|
pictureBox.Image = (Bitmap)temp;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void bGreyscale_Click(object sender, EventArgs e)
|
|
{
|
|
if (Bitmap)
|
|
{
|
|
// Convert the bitmap to 8bpp and greyscale
|
|
ReplaceBitmap(bitmap.GetColorConvertedInstance(
|
|
FREE_IMAGE_COLOR_DEPTH.FICD_08_BPP |
|
|
FREE_IMAGE_COLOR_DEPTH.FICD_FORCE_GREYSCALE));
|
|
}
|
|
}
|
|
|
|
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
|
|
{
|
|
ComboBox cb = sender as ComboBox;
|
|
if ((cb != null) && (cb.Items.Count > 0))
|
|
{
|
|
if (Bitmap)
|
|
{
|
|
try
|
|
{
|
|
// Switch the selected frame
|
|
bitmap.SelectActiveFrame(cb.SelectedIndex);
|
|
ReplaceBitmap(bitmap);
|
|
}
|
|
catch (ArgumentOutOfRangeException)
|
|
{
|
|
MessageBox.Show("Error changing frame.", "Error");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void bAdjustGamma_Click(object sender, EventArgs e)
|
|
{
|
|
if (Bitmap)
|
|
{
|
|
// Adjust the gamma value
|
|
bitmap.AdjustGamma((double)vGamma.Value);
|
|
ReplaceBitmap(bitmap);
|
|
}
|
|
}
|
|
|
|
private void bRedChannelOnly_Click(object sender, EventArgs e)
|
|
{
|
|
// Mask out green and blue
|
|
SetColorChannels(0xFF, 0x00, 0x00);
|
|
}
|
|
|
|
private void bGreenChannel_Click(object sender, EventArgs e)
|
|
{
|
|
// Mask out red and blue
|
|
SetColorChannels(0x00, 0xFF, 0x00);
|
|
}
|
|
|
|
private void bBlueChannel_Click(object sender, EventArgs e)
|
|
{
|
|
// Mask out red and green
|
|
SetColorChannels(0x00, 0x00, 0xFF);
|
|
}
|
|
|
|
private void bAllChannels_Click(object sender, EventArgs e)
|
|
{
|
|
if (Bitmap)
|
|
{
|
|
// Restore the bitmap using the original
|
|
ReplaceBitmap(bitmap);
|
|
}
|
|
}
|
|
|
|
private void SetColorChannels(int redmask, int greenmask, int bluemask)
|
|
{
|
|
if (Bitmap)
|
|
{
|
|
// Create a temporary clone.
|
|
using (FreeImageBitmap bitmap = (FreeImageBitmap)this.bitmap.Clone())
|
|
{
|
|
if (bitmap != null)
|
|
{
|
|
// Check whether the bitmap has a palette
|
|
if (bitmap.HasPalette)
|
|
{
|
|
// Use the Palette class to handle the bitmap's
|
|
// palette. A palette always consist of RGBQUADs.
|
|
Palette palette = bitmap.Palette;
|
|
// Apply the new values for all three color components.
|
|
for (int i = 0; i < palette.Length; i++)
|
|
{
|
|
RGBQUAD rgbq = palette[i];
|
|
|
|
rgbq.rgbRed = (byte)(rgbq.rgbRed & redmask);
|
|
rgbq.rgbGreen = (byte)(rgbq.rgbGreen & greenmask);
|
|
rgbq.rgbBlue = (byte)(rgbq.rgbBlue & bluemask);
|
|
|
|
palette[i] = rgbq;
|
|
}
|
|
}
|
|
// In case the bitmap has no palette it must have a color depth
|
|
// of 16, 24 or 32. Each color depth needs a different wrapping
|
|
// structure for the bitmaps data. These structures can be accessed
|
|
// by using the foreach clause.
|
|
else if (bitmap.ColorDepth == 16)
|
|
{
|
|
// Iterate over each scanline
|
|
// For 16bpp use either Scanline<FI16RGB555> or Scanline<FI16RGB565>
|
|
if (bitmap.IsRGB555)
|
|
{
|
|
foreach (Scanline<FI16RGB555> scanline in bitmap)
|
|
{
|
|
for (int x = 0; x < scanline.Length; x++)
|
|
{
|
|
FI16RGB555 pixel = scanline[x];
|
|
pixel.Red = (byte)(pixel.Red & redmask);
|
|
pixel.Green = (byte)(pixel.Green & greenmask);
|
|
pixel.Blue = (byte)(pixel.Blue & bluemask);
|
|
scanline[x] = pixel;
|
|
}
|
|
}
|
|
}
|
|
else if (bitmap.IsRGB565)
|
|
{
|
|
foreach (Scanline<FI16RGB565> scanline in bitmap)
|
|
{
|
|
for (int x = 0; x < scanline.Length; x++)
|
|
{
|
|
FI16RGB565 pixel = scanline[x];
|
|
pixel.Red = (byte)(pixel.Red & redmask);
|
|
pixel.Green = (byte)(pixel.Green & greenmask);
|
|
pixel.Blue = (byte)(pixel.Blue & bluemask);
|
|
scanline[x] = pixel;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (bitmap.ColorDepth == 24)
|
|
{
|
|
// Iterate over each scanline
|
|
// For 24bpp Scanline<RGBTRIPLE> must be used
|
|
foreach (Scanline<RGBTRIPLE> scanline in bitmap)
|
|
{
|
|
for (int x = 0; x < scanline.Length; x++)
|
|
{
|
|
RGBTRIPLE pixel = scanline[x];
|
|
pixel.rgbtRed = (byte)(pixel.rgbtRed & redmask);
|
|
pixel.rgbtGreen = (byte)(pixel.rgbtGreen & greenmask);
|
|
pixel.rgbtBlue = (byte)(pixel.rgbtBlue & bluemask);
|
|
scanline[x] = pixel;
|
|
}
|
|
}
|
|
}
|
|
else if (bitmap.ColorDepth == 32)
|
|
{
|
|
// Iterate over each scanline
|
|
// For 32bpp Scanline<RGBQUAD> must be used
|
|
foreach (Scanline<RGBQUAD> scanline in bitmap)
|
|
{
|
|
for (int x = 0; x < scanline.Length; x++)
|
|
{
|
|
RGBQUAD pixel = scanline[x];
|
|
pixel.rgbRed = (byte)(pixel.rgbRed & redmask);
|
|
pixel.rgbGreen = (byte)(pixel.rgbGreen & greenmask);
|
|
pixel.rgbBlue = (byte)(pixel.rgbBlue & bluemask);
|
|
scanline[x] = pixel;
|
|
}
|
|
}
|
|
}
|
|
// Dispose only the picturebox's bitmap
|
|
if (pictureBox.Image != null)
|
|
{
|
|
pictureBox.Image.Dispose();
|
|
}
|
|
pictureBox.Image = (Bitmap)bitmap;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void vRotate_Scroll(object sender, EventArgs e)
|
|
{
|
|
TrackBar bar = sender as TrackBar;
|
|
if (bar != null)
|
|
{
|
|
lRotate.Text = bar.Value.ToString();
|
|
}
|
|
}
|
|
|
|
private void nShowMetadata_Click(object sender, EventArgs e)
|
|
{
|
|
if (Bitmap)
|
|
{
|
|
MetaDataFrame mFrame = new MetaDataFrame();
|
|
mFrame.Tag = bitmap.Metadata;
|
|
mFrame.ShowDialog(this);
|
|
}
|
|
}
|
|
}
|
|
} |