0

I'm making a graphics editor for my class project and i want to make so that when, for example a user loads a picture in to the editor or or draw something in the PictureBox, all the alpha parts are shown the chessboard like background.

My idea is that when I create a PictureBox with transparent background set, I create another one behind it, set its BackColor to white and add grey images 50x50, alternately horizontally and vertically. Is that a good approach to the problem? If, not do You have any suggestions?

In Photoshop, for example, I create image 1600x1600. When I zoom to a certain level, it shrinks the boxes and adds more of them to fill the image. If You'we used Photoshop of similar program you know what I mean. Now, how would I go about achieving the same effect?

CodeBreaker
  • 488
  • 9
  • 18
  • Another idea, you could just draw the checkered background directly to the picturebox before user input is rendered to it. As for zoom, if your considered 100% zoom had a set size (such as your 50x50) for the checker cells, then giving the user a zoom option would simply alter your rendering of the checkers by the zoom factor. ( draw width = cell width * zoom%, draw height = cell height * zoom% ) Using the draw width and height you'd be able to calculate how many cells to draw to fill your picturebox. – OhBeWise Jan 16 '15 at 23:34
  • The chessboard pattern is simply implemented with two paints. You first draw the chessboard, then you draw the image. You can fight PictureBox to do it for you, that requires making the bottom one the Parent of the top one. Same code as [shown here](http://stackoverflow.com/a/9387562/17034). – Hans Passant Jan 16 '15 at 23:39
  • Thanks. I'll see what I can do. @OhBeWise would't the checkered background show when I save the picture? Or would I just have to remove the background before save? – CodeBreaker Jan 16 '15 at 23:53
  • @HansPassant by paints you mean two PictureBoxes or ? – CodeBreaker Jan 16 '15 at 23:55
  • I mean Graphics.FillRectangle() and Graphics.DrawImage(). Code. The opposite of moving controls around with a mouse. It will hurt for a bit when you cut the mouse umbilical cord, but only way to get ahead. – Hans Passant Jan 16 '15 at 23:58
  • Good point. I didn't consider the save. The answer Hans has provided makes one picturebox the parent of the other, giving the child transparency. The rest you'd still have to take care of as suggested. – OhBeWise Jan 17 '15 at 00:01
  • Thank you all, I'll be back when I start implementing Math part of the editor. @HansPassant that cord was severed yesterday when I had to dynamically show controls on the form. :) Since I started using C# forms yesterday (when I started this project), instead of sleeping on the lectures, I'm still a bit loose on the terms, like 'paints'. :) – CodeBreaker Jan 17 '15 at 00:46
  • It may help if you look at already existing Paint.NET to appreciate the architecture and the level of complexity. It always helps to have a look at someone else's work first, before trying to re-invent the wheel. Here is the link: http://www.codeproject.com/Articles/449519/Developer-Tools-Paint-NET – zmechanic Jan 17 '15 at 11:30

1 Answers1

2

Creating a Photoshop-like program is a fun project.

There will be many challenges along your way and it is well worth thinking ahead a little..

Here is a short and incomplete list of things to keep in mind:

  • Draw- and paint actions
  • Undo, redo, edit
  • Multiple layers
  • Zooming and scrolling
  • Saving and printing

So getting a checkerboard background is only the start of a long journey..

Using a PictureBox as the base canvas is a very good choice, as its several layers will help. Here is a piece of code that will provide you with a flexible checkerboard background, that will keep its size even when you scale the real graphics:

void setBackGround(PictureBox pb, int size, Color col)
{   
    if (size == 0 && pb.BackgroundImage != null)
    {
        pb.BackgroundImage.Dispose();
        pb.BackgroundImage = null;
        return;
    }
    Bitmap bmp = new Bitmap(size * 2, size * 2);
    using (SolidBrush brush = new SolidBrush(col))
    using (Graphics G = Graphics.FromImage(bmp) )
    {
        G.FillRectangle(brush, 0,0,size, size);
        G.FillRectangle(brush, size,size, size, size);
    }
    pb.BackgroundImage = bmp;
    pb.BackgroundImageLayout = ImageLayout.Tile;
}

Load an Image for testing and this is what you'll get, left normal, right zoomed in:

enter image description hereenter image description here

Yes, for saving this background should be removed; as you can see in the code, passing in a size = 0 will do that.

What next? Let me give you a few hints on how to approach the various tasks from above:

  • Scrolling: Picturebox can't scroll. Instead place it in a Panel with AutoScroll = true and make it as large as needed.

  • Zooming: Playing with its Size and the SizeMode will let you zoom in and out the Image without problems. The BackgroundImage will stay unscaled, just as it does in Photoshop. You will have to add some more code however to zoom in on the graphics you draw on top of the PB or on the layers. The key here is scaling the Graphics object using a Graphics.MultiplyTransform(Matrix).

  • Layers: Layers are imo the single most useful feature in PhotoShop (and other quality programs). They can be achieved by nesting transparent drawing canvases. Panels can be used, I prefer Labels. If each is sitting inside the one below it and the one at the bottom has the PB as its Parent, all their contents will be shown combined.

    • Don't use the Label directly but create a subclass to hold additional data and know-how!
    • Changing their order is not very hard, just keep the nested structure in mind and intact!
    • Hiding a layer is done by setting a flag and checking that flag in the painting actions
    • Other data can include a Name, Opacity, maybe an overlay color..
    • The layers should also be shown in a Layers Palette, best by creating a thumbnail and inserting a layer userobject in a FlowLayoutPanel
  • Draw Actions: These are always the key to any drawing in WinForms. When using the mouse to draw, each such activity creates an object of a DrawAction class you need to design, which holds all info needed to do the actual drawing, like:

    • Type (Rectangle, filledRectangle, Line, FreeHandLine (a series of Points), Text, etc.etc..)
    • Colors
    • Points
    • Widths
    • Text
    • The layer to draw on
    • maybe even a rotation

    Along with the LayerCanvas class the DrawAction class will be the most important class in the project, so getting its design right is worth some work!

    Only the topmost layer will receive the mouse events. So you need to keep track which layer is the active one and add the action to its actions list. Of course the active layer must also be indicated in the Layers Palette.

  • Since all drawing is stored in List(s), implementing a unlimited undo and redo is simple. To allow for effective drawing and undo, maybe a common action list and an individual list for each layer is the best design..

    • Undo and Redo are just matter of removing the last list element and pushing it onto a redo-stack.
    • Editing actions is also possible, including changing the parameters, moving them up or down the actions list or removing one from the middle of the list. It help to show an Actions Palette, like F9 in PhotoShop.
    • To flatten two or more layers together all you need is to combine their action lists.
    • To flatten all layers into the Image you only need to draw them not onto their canvas but into the Image. For the difference of drawing onto a control or into a Bitmap see here! Here we have the PictureBox.Image as the second level of a PB's structure above the Background.Image. (The 3rd is the Control surface, but with the multiple layers on top we don't really need it..)
  • Saving can be done by either by Image.Save() after flattening all Layers or after you have switched off the BackgroundImage by telling the PB to draw itself into a Bitmap ( control.DrawToBitmap() ) which you can then save.

Have fun!

Community
  • 1
  • 1
TaW
  • 53,122
  • 8
  • 69
  • 111
  • Thank you very much for the lengthy response. Scroling: I added tabControl, since I want multiple projects open, so when a user add a new file it creates pictureBox, adds to TabPage (AntoScroll = ture) and then adds it to the tabControl. Layers: What would be the benefit of using labels instead of pictureboxes, as I was planing to use.? – CodeBreaker Jan 17 '15 at 13:57
  • I usually try to keep things simple and the PictureBox is a bit more powerful/expensive; but, especially if you draw into their Images you may save some effort when zooming. But if you draw onto the suface it doesn't matter much.. – TaW Jan 17 '15 at 14:28