Crazy Paint

by James Hall: L6 Age ~17

Introduction

You can use program CrazyPaint to draw lines of different thickness using the mouse, flood-fill, erase, save files and load files. James has written his own Jline procedure to draw lines. New users will be able to create graphics with the program intuitively; standard icons represent the buttons. A click on the save icon executes program saveall using the exec procedure available in the dos unit. James developed his version of a combo box in which you can select from available filenames or type in a new one. Program loadall works similarly. Follow the links at the bottom of this page for further details and the code of these auxiliary programs.

The following screenshot shows the program in action.

Crazy painting

Crazy painting

In order to run programs CrazyPaint, saveall and loadall, you will need to have downloaded Stefan Berinde`s wingraph.zip file as described in our Graphics tutorial. You should copy the unzipped wincrt.pas, winmouse,pas and wingraph.pas (from the src folder) into your program folder. (The compiled units are included in the zip file but you might as well have the source code available for reference). You should find these files useful for your own graphics programs.

The three programs also need the Icons and savedata folders of files and program CrazyPaint needs saveall.exe and loadall.exe. Download the source code for programs CrazyPaint, saveall and loadall together with these folders in crazypaint.zip.

We have added comments to these programs.

The Program

program CrazyPaint;
{
    Copyright (c) 2011 James Hall

    Licensed under the Apache License, Version 2.0 (the "License"); you may not
    use this file except in compliance with the License, as described at
    http://www.apache.org/licenses/ and http://www.pp4s.co.uk/licenses/
}
{$mode objfpc}{$H+}
{$APPTYPE GUI}
uses
  Classes, SysUtils, wingraph, wincrt, winmouse, dos;
var
  mousex, mousey, obx, oby, i, j, drawmode, memorysize, pencilsize, check : integer;
  Gd, Gm : smallint;
  screen : array[1 .. 1200, 1 .. 800] of integer;
  mybitmap : file;
  datafile : textfile;
  bitmap : pointer;
  m : real;
  currname : string;

procedure setblankscr;
begin
  for i := 1 to 1200 do
    for j := 1 to 800 do
      screen[i, j] := 0; //Screen will be used to store actions to be carried out upon mouse clicks.
end;

procedure drawbutton(x1, x2, y1, y2, colour, actnum : integer);
begin
  case colour of
    0 : setfillstyle(solidfill, white);
    1 : setfillstyle(solidfill, red);
    2 : setfillstyle(solidfill, blue);
    3 : setfillstyle(solidfill, yellow);
    4 : setfillstyle(solidfill, pink);
    5 : setfillstyle(solidfill, black);
  end;
  fillRect(x1, y1, x2, y2);
  for i := x1 to x2 do
    for j := y1 to y2 do
      if (i > 0) AND (i < 1201) AND (j > 0) AND (j < 801) then
        screen[i, j] := actnum; //Actions to be used in case statement
end;

procedure Jline(x1, y1, x2, y2, thick : integer);
begin
 //drawing a line from 0,0 to x2-x1, y2-y1
 //find  rounded y value when inc x from 0 to x2-x1
 // y = mx
  if (x2 - x1) > 0 then
    begin
      m := (y2 - y1) / (x2 - x1);
      for i := 0 to (x2 - x1) do
        begin
          fillrect(i - (thick - 1) + x1, round(m * i) - (thick - 1) + y1, i + (thick - 1) + x1, round(m * i) + (thick - 1) + y1);
        end;
      if (y2 - y1) <> 0 then
        begin
          for i := 0 to (y2 - y1) do
            begin
              fillrect(round(i / m)-(thick - 1) + x1, i - (thick - 1) + y1, round(i / m) + (thick - 1) + x1, i + (thick - 1)+ y1);
           end;
        end;
      if (y2 - y1) < 0 then
        begin
          for i := 0 to (y1 - y2) do
            begin
              fillrect(round(-i / m)-(thick - 1) + x1, -i - (thick - 1) + y1, round(-i / m) + (thick - 1) + x1, -i + (thick - 1) + y1);
            end;
        end;
    end;
  if (x2 - x1) < 0 then
    begin
      m := (y2 - y1) / (x2 - x1);
      for i := 0 to (x1 - x2) do
        begin
          fillrect(-i -(thick - 1) + x1, round(-m * i) - (thick - 1) + y1, -i + (thick - 1) + x1, round(-m * i)+(thick - 1) + y1);
        end;
      if (y2 - y1) > 0 then
        begin
          for i := 0 to (y2 - y1) do
            begin
              fillrect(round(i / m) - (thick - 1) + x1, i - (thick - 1) + y1, round(i / m) + (thick - 1) + x1, i + (thick - 1) + y1);
            end;
        end;
      if (y2 - y1) < 0 then
        begin
          for i := 0 to (y1 - y2) do
            begin
              fillrect(round(-i / m) - (thick - 1) + x1, -i - (thick - 1) + y1, round(-i / m) + (thick - 1) + x1, -i + (thick - 1) + y1);
            end;
        end;
    end;
  if (x2 - x1) = 0 then
    begin
      if (y2 - y1) < 0 then
        begin
          for i := 0 to (y1 - y2) do
            begin
              fillrect(-(thick - 1) + x1, -i - (thick - 1) + y1, (thick - 1) + x1, -i + (thick - 1) + y1);
            end;
        end;
      if (y2 - y1) >= 0 then
        for i := 0 to (y2 - y1) do
          begin
            fillrect(-(thick - 1) + x1, i - (thick - 1) + y1, (thick - 1) + x1, i + (thick - 1) + y1);
          end;
    end;
end;

procedure puticon (x, y : integer; name : string);
begin
  memorysize := imageSize(0, 0, 29, 29);
  getMem(bitmap, memorysize);
  assign(mybitmap, name);
  reset(mybitmap, 1);
  blockread(mybitmap, bitmap^, memorysize);
  close(mybitmap);
  putimage(x, y, bitmap^, copyput);
  freeMem(bitmap, memorysize);
end;

begin
  Gd := 3;
  gm := 13;
  //SetWindowSize(1000, 700);
  SetWindowSize(900, 600);
  initgraph(Gd, gm, 'Crazy Paint');
  obx := 100;
  oby := 100;
  mousex := Getmousex;
  mousey := Getmousey;
  obx := mousex;
  oby := mousey;
  drawmode := 1;
  setblankscr;
  //PPS: Next 2 lines added by us
  setfillstyle(solidfill, LightGray);
  bar(1, 1, 900, 600);
  setcolor(darkkhaki);

  drawbutton(50, 700, 50, 450, 0, 1);  //button 1 is the canvas
  setcolor(white);
  drawbutton(780, 800, 100, 120, 1, 2);  //button 2 is red ink
  drawbutton(780, 800, 130, 150, 2, 3);  //button 3 is blue ink
  drawbutton(780, 800, 160, 180, 3, 4);  //button 4 is yellow ink
  drawbutton(785, 815, 360, 390, 4, 5);  //button 5 is eraser

  drawbutton(785, 815, 200, 230, 2, 7);  //button 7 is pencil button
  drawbutton(785, 815, 240, 270, 3, 8);  //button 8 is the fill button
  drawbutton(100, 130, 470, 500, 0, 9);  //button 9 is the save button
  drawbutton(140, 170, 470, 500, 2, 10);  //button 10 is the load button
  drawbutton(150, 180, 510, 540, 1, 11);  //button 11 is a pencil size button
  drawbutton(190, 220, 510, 540, 1, 12);  //button 12 is a pencil size button
  drawbutton(230, 260, 510, 540, 1, 13);  //button 13 is a pencil size button
  drawbutton(810, 830, 100, 120, 0, 14);  //button 14 is white ink
  drawbutton(810, 830, 130, 150, 4, 15);  //button 15 is pink ink
  drawbutton(810, 830, 160, 180, 5, 16);  //button 16 is black ink

  puticon(785, 200, 'Icons/pencil.bmp');
  puticon(785, 240, 'Icons/fillcan.bmp');
  puticon(100, 470, 'Icons/save.bmp');
  puticon(140, 470, 'Icons/load.bmp');
  puticon(150, 510, 'Icons/size1x.bmp');
  puticon(190, 510, 'Icons/size2x.bmp');
  puticon(230, 510, 'Icons/size3x.bmp');
  puticon(230, 510, 'Icons/size3x.bmp');
  puticon(785, 360, 'Icons/eraser.bmp');

  setcolor(red);
  setfillstyle(solidfill, red);
  pencilsize := 2;

  repeat
    mousex := Getmousex;
    mousey := Getmousey;

    case getmousebuttons of
      MouseLeftButton: begin
                         case screen[mousex, mousey] of
                           1 : begin
                                 case drawmode of
                                   1 : Jline(obx, oby, mousex, mousey, pencilsize);
                                   2 : begin
                                         setfloodmode(1);
                                         floodfill(mousex, mousey, getpixel(mousex, mousey));
                                       end;
                                   3 : Jline(obx, oby, mousex, mousey, pencilsize);
                                 end;
                               end;
                           2 : begin
                                 setcolor(red);
                                 setfillstyle(solidfill, red);
                               end;
                           3 : begin
                                 setcolor(blue);
                                 setfillstyle(solidfill, blue);
                               end;
                           4 : begin
                                 setcolor(yellow);
                                 setfillstyle(solidfill, yellow);
                               end;
                           5 : begin
                                 drawmode := 3;
                                 setcolor(white);
                                 setfillstyle(solidfill, white);
                               end;

                           7 : drawmode := 1;
                           8 : drawmode := 2;
                           9 : begin
                                 exec('saveall.exe', '');
                                 //Confirm that directories are set up and that saveall.exe code has run.
                                 assignfile(datafile, 'savedata/saveint.txt');
                                 reset(datafile);
                                 readln(datafile, check);
                                 closefile(datafile);
                                 if check = 1 then
                                   begin
                                     //Retrieve the filename saved by saveall.exe
                                     assignfile(datafile, 'savedata/allnames.txt');
                                     reset(datafile);
                                     readln(datafile, currname); //Do not use the first line
                                     readln(datafile, currname);
                                     closefile(datafile);
                                     //Save bitmap image to file with filename saved by saveall.exe
                                     memorysize := imageSize(50, 50, 700, 450);
                                     getMem(bitmap, memorysize);
                                     getImage(50, 50, 700, 450, bitmap^);
                                     assign(mybitmap, 'savedata/' + currname + '.bmp');
                                     rewrite(mybitmap, 1);
                                     blockwrite(mybitmap, bitmap^, memorysize);
                                     close(mybitmap);
                                     freeMem(bitmap, memorysize);
                                   end;
                               end;
                          10 : begin
                                 exec('loadall.exe','');
                                 //Confirm that directories are set up and that loadall.exe code has run.
                                 assignfile(datafile, 'savedata/saveint.txt');
                                 reset(datafile);
                                 readln(datafile, check);
                                 closefile(datafile);
                                 if check = 1 then
                                   begin
                                     //Retrieve the filename saved by loadall.exe
                                     assignfile(datafile, 'savedata/allnames.txt');
                                     reset(datafile);
                                     readln(datafile, currname);
                                     readln(datafile, currname);
                                     closefile(datafile);
                                     //Load bitmap image from file with filename saved by loadall.exe
                                     memorysize := imageSize(50, 50, 700, 450);
                                     getMem(bitmap, memorysize);
                                     assign(mybitmap,'savedata/' + currname + '.bmp');
                                     reset(mybitmap, 1);
                                     blockread(mybitmap, bitmap^, memorysize);
                                     close(mybitmap);
                                     putimage(50, 50, bitmap^, copyput);
                                     freeMem(bitmap, memorysize);
                                   end;
                               end;
                          11 : pencilsize := 2;
                          12 : pencilsize := 3;
                          13 : pencilsize := 8;
                          14 : begin
                                 setcolor(white);
                                 setfillstyle(solidfill, white);
                               end;
                          15 : begin
                                 setcolor(pink);
                                 setfillstyle(solidfill, pink);
                               end;
                          16 : begin
                                 setcolor(black);
                                 setfillstyle(solidfill, black);
                               end;
                         end;
                       end;
    end;
    obx := mousex;
    oby := mousey;
  until closegraphrequest;
end.

Remarks

Could you write your own paint program or extend the range of colours available in this one?

Programming - a skill for life!

Seven programs including GameOfLife, PixelSort and SuperHappyFunLand by James Hall