3
votes

Okay. Here is the source code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;

namespace PictureMaker
{
class Program
{
    static void Main()
    {
        int[] WorkingSet = new int[2] { 1, 1 }; //used for rng
        int[] Pixel = new int[3] { 0, 0, 0 }; // rgb value of pixel from rng
        byte[] Data; //raw data to be put into memory
        int Height; //height of final image
        int Width; //width of final image
        Bitmap Picture; //picture to save
        string Input; //input storage string
        int RandomNumber = 0; //inital random number
        byte[] MinorData; //temporary data storage

        Console.WriteLine("Seed 1 (100 to 999, whole numbers only):");
        Input = Console.ReadLine(); //gets input
        WorkingSet[0] = int.Parse(Input); //parses to variable
        Console.WriteLine("Seed 2 (100 to 999, whole numbers only):");
        Input = Console.ReadLine();
        WorkingSet[1] = int.Parse(Input);
        Console.WriteLine("Height (whole numbers only):");
        Input = Console.ReadLine();
        Height = int.Parse(Input);
        Console.WriteLine("Width (whole numbers only):");
        Input = Console.ReadLine();
        Width = int.Parse(Input);

        Data = new byte[Height * Width * 4]; //width times height times pixel byte depth makes total bytes required to store the image.

        for (int i = (Height * Width * 4) - 1; i >= 0; i = i - 4) //each loop makes a single pixel, so it creates 4 bytes. Starting with the last pixel and moving to the first pixel.
        {
            WorkingSet = GenerateRandomNumber(WorkingSet);
            RandomNumber = WorkingSet[1]; //uses the second (fresh) number from the working set to use in making the pixel.
            MinorData = GeneratePixel(RandomNumber); //assigns pixel data to the temporary storage

            Data[i] = (byte)0;  //alpha channel is always 0 (I hope)
            Data[i - 1] = MinorData[2];
            Data[i - 2] = MinorData[1]; //remember this is backwards. last pixel to first pixel.
            Data[i - 3] = MinorData[0];
        }

        IntPtr Pointer = System.Runtime.InteropServices.Marshal.AllocHGlobal((Height * Width) * 4); //?? assigns the proper number of bytes to be stored in memory at this location ?? no idea honestly
        for (int i = (Height * Width * 4) - 1; i >= 0; i = i - 1) //iderates through each byte in the data...
        {
            System.Runtime.InteropServices.Marshal.WriteByte(Pointer, i + 1, Data[i]); //... and writes them one at a time to the 'reserved memory'; also hopefully moves the writer to a 'fresh' memory byte each time. No idea.
        }

        try //put all this here because it was crashing.
        {
            Picture = new Bitmap(Width, Height, Width * 4, System.Drawing.Imaging.PixelFormat.Canonical, Pointer); //invalid parameter. 
            Picture.Save("MyPicture.bmp");
        }
        catch (ArgumentException s)
        {
            Console.WriteLine(s);
        }
        Console.ReadLine(); //keeps program from closing on completion.
    }

    static byte[] GeneratePixel(int RandomNumber)
    {
        //*28
        char[] CharArray; //for working with the number
        byte[] PixelData = new byte[3]; //for return
        CharArray = (RandomNumber.ToString().ToCharArray()); //converts number to string then breaks down to chars
        PixelData[0] = (byte)(int.Parse(CharArray[0].ToString())*28); //converts chars to string to number and multiplies by 28 then converts the 255 RGB int to a byte
        PixelData[1] = (byte)(int.Parse(CharArray[1].ToString())*28);
        PixelData[2] = (byte)(int.Parse(CharArray[2].ToString())*28);
        return PixelData;
    }

    static int[] GenerateRandomNumber(int[] WorkingSet)
    {
        int[] RandomNumber = new int[2]; //for return
        string RandomString; //for working
        RandomNumber[0] = WorkingSet[1]; //makes 2nd working set number the first
        RandomString = (WorkingSet[0] + WorkingSet[1]).ToString(); //generates next number
        RandomNumber[1] = int.Parse(RandomString.Substring(RandomString.Length - 3)); //gets last 3 numbers and assigns it to 2nd slot
        return RandomNumber; //returns as the new working set
    }
}
}

I am trying to procedurally generate a picture (call it abstract art), and write it to the disk. I don't really want help on the procedurally generated part. I want help getting my image to the disk.

The only thing that Visual Studio gives me is this:

System.ArgumentException: Parameter is not valid. at System.Drawing.Bitmap..ctor(Int32 width, Int32 height, Int32 stride, PixelFormat format, IntPtr scan0)

2
What is the Width and Height you gave?CharithJ
I tried with both 1x1 and 4x4.UpTide

2 Answers

1
votes

Probably your Width and Height too high. Try with smaller width and height (600x800) and see. .NET may refuse to create an image that uses up that much contiguous memory all at once.

1
votes

Well, I started your code with 100x200 size. And sids 200-300. I didn't catch your error, but found another :

System.AccessViolationException: Attempted to read or write protected memory

To fix it I changed PixelFormat to Format32bppRgb:

 Picture = new Bitmap(Width, Height, Width * 4, System.Drawing.Imaging.PixelFormat.Format32bppRgb, Pointer); //invalid parameter. 

It occured because some types of PixelFormat causes ArgumentException when passed to new Bitmap(). Here is list of these types:

  • Gdi
  • Alpha
  • PAlpha
  • Extended
  • Canonical
  • Undefined
  • DontCare