PGM Viewer - C# Programming Exercise

The PGM format is one of the versions of the NetPBM image formats. Specifically, it is the variant capable of handling images in shades of gray. Its header starts with a line containing P2 (if the image data is in ASCII) or P5 (if it is in binary).

The second line contains the width and height, separated by a space. The third line contains the intensity value that corresponds to the target (typically 255, although it could also be 15 or another value).

From there, the colors (shades of gray) of the points that make up the image begin. In ASCII format (P2), they are numbers from 0 to 255 separated by spaces and possibly newlines. In binary format (P5), they are contiguous bytes, from 0 (black) to 255 (white).

You need to create a program capable of reading a binary PGM file (header P5), without comments, with 255 shades of gray (but with varying width and height). Additionally, you must represent the colors (shades of gray) in the console as follows:

If the gray intensity is greater than 200, you will draw a blank space.
If it is between 150 and 199, you will draw a dot.
If it is between 100 and 149, you will draw a dash (-).
If it is between 50 and 99, you will draw an equals sign (=).
If it is between 0 and 49, you will draw a pound sign (#).

The name of the file to be analyzed must be read from the command line, not prompted by the user or pre-set.

Note: line breaks (\n) are represented by ASCII character 10 (0x0A).

 Category

File Management

 Exercise

PGM Viewer

 Objective

The PGM format is one of the versions of NetPBM image formats. Specifically, it is the variant capable of handling images in shades of gray.

Its header begins with a line containing P2 (if the image data is in ASCII) or P5 (if it is in binary).

The second line contains the width and height, separated by a space.

A third line contains the intensity value that corresponds to the target (typically 255, although it could also be 15 or another value).

From there, the colors (shades of gray) of the points that make up the image begin. In ASCII format (P2), they are numbers from 0 to 255 separated by spaces and perhaps newlines. In binary (P5) format, they are contiguous bytes, from 0 (black) to 255 (white).

You must create a program capable of reading a file in binary PGM format (header P5), without comments, with 255 shades of gray (but with a width and height that can vary). In addition, you must represent the colors (shades of gray) in the console as follows:

If the intensity of gray is greater than 200, you will draw a blank space.
If it is between 150 and 199, you will draw a point.
If it is between 100 and 149, you will draw a dash (-).
If it is between 50 and 99, you will draw an "equals" symbol (=).
If it is between 0 and 49, you will draw a pound sign (#).
The name of the file to be analyzed must be read from the command line, not prompted by the user or pre-set.

Note: line breaks (\n) are represented by character 10 of the ASCII code (0x0A).

 Write Your C# Exercise

// Importing the System namespace to use its classes
using System; 

using System.IO; // Importing the IO namespace to handle file operations

class PgmViewer
{
    // The main method, where the program execution begins
    static void Main(string[] args)
    {
        // Check if a file name has been provided as a command-line argument
        if (args.Length < 1)
        {
            // Display an error message if no file name is provided
            Console.WriteLine("You must provide a PGM file as an argument.");
            return; // Exit the program if no file is provided
        }

        // Retrieve the file name from the command-line arguments
        string fileName = args[0];

        try
        {
            // Read the entire PGM file into a byte array
            byte[] pgmData = File.ReadAllBytes(fileName);

            // Check if the file begins with "P5" to ensure it's a binary PGM file
            if (pgmData[0] != 'P' || pgmData[1] != '5')
            {
                // Display an error message if the file is not in PGM binary format
                Console.WriteLine("The file is not a binary PGM (P5) file.");
                return; // Exit the program if the format is incorrect
            }

            // Set the offset to start reading the header after "P5"
            int offset = 2; // Skip the first two characters "P5"

            // Read the image width and height, skipping spaces or newlines
            while (pgmData[offset] == 10 || pgmData[offset] == 32) offset++; // Skip spaces and newlines

            int width = 0, height = 0; // Initialize width and height of the image
            while (pgmData[offset] >= 48 && pgmData[offset] <= 57) width = width * 10 + (pgmData[offset++] - 48); // Read width (digits)
            while (pgmData[offset] == 32) offset++; // Skip the space between width and height
            while (pgmData[offset] >= 48 && pgmData[offset] <= 57) height = height * 10 + (pgmData[offset++] - 48); // Read height (digits)

            // Skip spaces or newlines before reading the max pixel value
            while (pgmData[offset] == 10 || pgmData[offset] == 32) offset++; // Skip spaces and newlines

            int maxValue = 0; // Initialize the max intensity value (typically 255)
            while (pgmData[offset] >= 48 && pgmData[offset] <= 57) maxValue = maxValue * 10 + (pgmData[offset++] - 48); // Read the max value (digits)

            // The image data starts after the header, so we copy it to a separate array
            byte[] pixelData = new byte[width * height]; // Allocate space for the pixel data
            Array.Copy(pgmData, offset, pixelData, 0, pixelData.Length); // Copy the pixel data into the array

            // Now we process and display the pixel data in the console
            for (int i = 0; i < pixelData.Length; i++)
            {
                int intensity = pixelData[i]; // Get the intensity value for the current pixel

                // Determine the character to print based on the intensity value
                char displayChar = intensity > 200 ? ' ' :  // If intensity is greater than 200, print a space
                                   (intensity >= 150) ? '.' :  // If intensity is between 150 and 199, print a dot
                                   (intensity >= 100) ? '-' :  // If intensity is between 100 and 149, print a dash
                                   (intensity >= 50) ? '=' :   // If intensity is between 50 and 99, print an equals sign
                                   '#';                        // If intensity is between 0 and 49, print a hash sign

                // Print the character for the current pixel
                Console.Write(displayChar);

                // If we've reached the end of a row, print a new line
                if ((i + 1) % width == 0)
                {
                    Console.WriteLine(); // Move to the next line after each row of pixels
                }
            }
        }
        catch (Exception ex)
        {
            // Display an error message if an exception occurs during file processing
            Console.WriteLine($"Error processing the file: {ex.Message}");
        }
    }
}

 Share this C# exercise

 More C# Programming Exercises of File Management

Explore our set of C# programming exercises! Specifically designed for beginners, these exercises will help you develop a solid understanding of the basics of C#. From variables and data types to control structures and simple functions, each exercise is crafted to challenge you incrementally as you build confidence in coding in C#.

  •  Display BMP on console V2

    In this exercise, you are asked to develop a program in C# that can display a 72x24 BMP file on the console. To do this, you must use the information contained...

  •  Writing to a text file

    In this exercise of C#, you need to create a program that asks the user for several sentences (until they just press Enter without typing anything) and stores those s...

  •  Appending to a text file

    In this exercise of C#, you need to create a program that asks the user for several sentences (until they just press Enter without typing anything) and stores those s...

  •  Display file contents

    In this exercise of C#, you need to create a program that displays all the contents of a text file on the screen. The file name will either be entered via the command...

  •  Extended TextToHTML (files)

    In this exercise of C#, you need to expand the TextToHtml class so that it can dump its result to a text file. You should create a ToFile method that ta...

  •  Logger

    In this exercise of C#, you need to create a Logger class with a static Write method, which will append a certain text to a log file. The method should ...