Click here to Skip to main content
15,885,365 members
Articles / Programming Languages / C#
Tip/Trick

Custom black and white Image Format

Rate me:
Please Sign up or sign in to vote.
4.00/5 (3 votes)
20 Nov 2022CPOL 4.7K   3   8
Custom black and white image format
This class was created to find a way to write/read PBM Image format.
C#
using System;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.Serialization.Formatters.Binary;
namespace Chico
{
    [Serializable]
    public sealed class CPBM
    {
        private bool[,] pixels;
        /// <summary>
        /// Represents a <see langword="null"/> <see cref="CPBM"/>.
        /// </summary>
        public static readonly CPBM Null = new CPBM(0, 0);
        private CPBM(int width, int height)
        {
            if (width <= 0 || height <= 0)
                return;
            this.pixels = new bool[width, height];
        }
        /// <summary>
        /// Load a <see cref="CPBM"/> from the specified stream.
        /// </summary>
        /// <returns>The cpbm from stream.</returns>
        /// <param name="stream">Stream.</param>
        public static CPBM Load(Stream stream)
        {
            BinaryFormatter decompressionFormatter = new BinaryFormatter();
            byte[] compressedBytes = null;
            using (MemoryStream compressionReader = new MemoryStream())
            {
                stream.CopyTo(compressionReader);
                compressedBytes = compressionReader.ToArray();
            }
            Array.Reverse(compressedBytes);
            using (MemoryStream decompressionStream = new MemoryStream(compressedBytes.Decompress()))
                return (CPBM)decompressionFormatter.Deserialize(decompressionStream);
        }
        /// <summary>
        /// Save this <see cref="CPBM"/> to the specified stream.
        /// </summary>
        /// <param name="stream">Stream.</param>
        public void Save(Stream stream)
        {
            byte[] cpbmData = null;
            using (MemoryStream cpbmWriter = new MemoryStream())
            {
                BinaryFormatter cpbmFormatter = new BinaryFormatter();
                cpbmFormatter.Serialize(cpbmWriter, this);
                cpbmData = cpbmWriter.ToArray();
            }
            byte[] compressedCpbm = cpbmData.Compress();
            Array.Reverse(compressedCpbm);
            stream.Write(compressedCpbm, 0, compressedCpbm.Length);
        }
        /// <summary>
        /// Gets or sets the level.
        /// </summary>
        /// <value>The level.</value>
        public int Level { get; set; }
        /// <summary>
        /// Gets the width of this <see cref="CPBM"/>.
        /// </summary>
        /// <value>The width.</value>
        public int Width => this.pixels.GetLength(0);
        /// <summary>
        /// Gets the height of this <see cref="CPBM"/>.
        /// </summary>
        /// <value>The height.</value>
        public int Height => this.pixels.GetLength(1);
        /// <summary>
        /// Gets the pixel at the specified coordinates of this <see cref="CPBM"/>.
        /// </summary>
        /// <returns><c>true</c>, if pixel was gotten, <c>false</c> otherwise.</returns>
        /// <param name="x">The x coordinate.</param>
        /// <param name="y">The y coordinate.</param>
        public bool GetPixel(int x, int y) => this.pixels[x, y];
        /// <summary>
        /// Sets the requested pixel at the specified coordinates.
        /// </summary>
        /// <param name="x">The x coordinate.</param>
        /// <param name="y">The y coordinate.</param>
        /// <param name="value">If set to <c>true</c> value.</param>
        public void SetPixel(int x, int y, bool value) => this.pixels[x, y] = value;
        private Color GetColor(int x, int y) => this.pixels[x, y] ? Color.White : Color.Black;
        /// <summary>
        /// Load a <see cref="CPBM"/> from the specified bitmap.
        /// </summary>
        /// <param name="bitmap">Bitmap.</param>
        /// <param name="useColorCorrectionProfile">If set to <c>true</c> use Color Correction Profile.</param>
        public void FromBitmap(Bitmap bitmap, bool useColorCorrectionProfile = false)
        {
            if (bitmap == null)
                return;
            this.pixels = new bool[bitmap.Width, bitmap.Height];
            for (int x = 0; x < bitmap.Width; x++)
            {
                for (int y = 0; y < bitmap.Height; y++)
                {
                    Color c = bitmap.GetPixel(x, y);
                    bool adjust = (c.R + c.G + c.B) >= Level;
                    if (!useColorCorrectionProfile)
                        this.SetPixel(x, y, !adjust);
                    else
                        this.SetPixel(x, y, adjust);
                }
            }
        }
        /// <summary>
        /// Saves a copy of this <see cref="CPBM"/> as a <see cref="Bitmap"/>.
        /// </summary>
        /// <param name="path">Path.</param>
        public void ToBitmap(string path)
        {
            try
            {
                this.ToBitmap().Save(path);
            }
            catch
            {
                return;
            }
        }
        public static explicit operator Bitmap(CPBM cPBM) => cPBM?.ToBitmap();
        private Bitmap ToBitmap()
        {
            Bitmap bitmap = new Bitmap(Width, Height);
            for (int x = 0; x < bitmap.Width; x++)
            {
                for (int y = 0; y < bitmap.Height; y++)
                {
                    bitmap.SetPixel(x, y, this.GetColor(x, y));
                }
            }
            using (MemoryStream ms = new MemoryStream())
            {
                bitmap.Save(ms, ImageFormat.Gif);
                ms.Seek(0, SeekOrigin.Begin);
                return (Bitmap)Image.FromStream(ms);
            }
        }
    }
}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
I do not claim to be wrong! I just rarely ever write.

Comments and Discussions

 
PraiseMy vote of 5 Pin
Stylianos Polychroniadis24-Nov-22 13:51
Stylianos Polychroniadis24-Nov-22 13:51 
GeneralRe: My vote of 5 Pin
charles henington25-Nov-22 0:51
charles henington25-Nov-22 0:51 
QuestionPlease describe the format Pin
YDaoust22-Nov-22 2:44
YDaoust22-Nov-22 2:44 
AnswerRe: Please describe the format Pin
charles henington22-Nov-22 15:22
charles henington22-Nov-22 15:22 
GeneralRe: Please describe the format Pin
YDaoust22-Nov-22 20:45
YDaoust22-Nov-22 20:45 
GeneralRe: Please describe the format Pin
charles henington22-Nov-22 23:44
charles henington22-Nov-22 23:44 
It's pretty simple. The bool[,] matrix represents a black or white pixel(true or false).
When saved to file(it can be saved as CPBM or as Bitmap). As a Bitmap it returns a black and white gif and as a CPBM it saves a copy of CPBM class using System.Runtime.Serialization.Formatters.Binary.BinaryFormatter, Compresses the output using System.IO.Compression.GZipStream and reverses the byte array of the compressed data before saving to file.
Here are the Compression and Decompression Methods from my Extensions class.

public static byte[] Compress(this byte[] array)
        {
            using (var compressedStream = new MemoryStream())
            using (var zipStream = new GZipStream(compressedStream, CompressionMode.Compress))
            {
                zipStream.Write(array, 0, array.Length);
                zipStream.Close();
                return compressedStream.ToArray();
            }
        }
        public static byte[] Decompress(this byte[] array)
        {
            using (var compressedStream = new MemoryStream(array))
            using (var zipStream = new GZipStream(compressedStream, CompressionMode.Decompress))
            using (var resultStream = new MemoryStream())
            {
                zipStream.CopyTo(resultStream);
                return resultStream.ToArray();
            }
        }


modified 23-Nov-22 6:10am.

GeneralRe: Please describe the format Pin
YDaoust23-Nov-22 3:40
YDaoust23-Nov-22 3:40 
GeneralRe: Please describe the format Pin
charles henington23-Nov-22 18:21
charles henington23-Nov-22 18:21 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.