Фотошоп как фон на прозрачном изображении

Я делаю графический редактор для своего проекта класса, и я хочу сделать так, чтобы, например, когда пользователь загружал изображение в редактор или рисовал что-то в PictureBox, все альфа-части отображались как шахматная доска как фон.

Моя идея заключается в том, что когда я создаю PictureBox с установленным прозрачным фоном, я создаю еще один за ним, устанавливаю его BackColor на белый и добавляю серые изображения 50x50, попеременно по горизонтали и вертикали. Это хороший подход к проблеме? Если нет, то есть ли у Вас какие-либо предложения?

В фотошопе, например, я создаю изображение 1600x1600. Когда я увеличиваю масштаб до определенного уровня, он сжимает поля и добавляет их, чтобы заполнить изображение. Если Вы использовали Photoshop или аналогичную программу, то понимаете, о чем я. Теперь, как я могу добиться того же эффекта?


person CodeBreaker    schedule 16.01.2015    source источник
comment
Еще одна идея: вы можете просто нарисовать клетчатый фон непосредственно в окне изображения, прежде чем пользовательский ввод будет отображаться на нем. Что касается масштабирования, если ваш предполагаемый 100%-й масштаб имеет заданный размер (например, 50x50) для ячеек шашки, то предоставление пользователю опции масштабирования просто изменит ваш рендеринг шашек с помощью коэффициента масштабирования. (ширина отрисовки = ширина ячейки * масштабирование%, высота отрисовки = высота ячейки * масштабирование% ). Используя ширину и высоту отрисовки, вы сможете рассчитать, сколько ячеек нужно отрисовать, чтобы заполнить окно изображения.   -  person OhBeWise    schedule 17.01.2015
comment
Рисунок шахматной доски просто реализуется двумя красками. Вы сначала рисуете шахматную доску, потом рисуете изображение. Вы можете бороться с PictureBox, чтобы сделать это за вас, для этого нужно сделать нижний родительским элементом верхнего. Тот же код, что и здесь.   -  person Hans Passant    schedule 17.01.2015
comment
Спасибо. Я посмотрю что я могу сделать. @OhBeWise не будет отображаться клетчатый фон, когда я сохраняю изображение? Или мне просто нужно удалить фон перед сохранением?   -  person CodeBreaker    schedule 17.01.2015
comment
@HansPassant под красками вы имеете в виду два PictureBox или ?   -  person CodeBreaker    schedule 17.01.2015
comment
Я имею в виду Graphics.FillRectangle() и Graphics.DrawImage(). Код. Противоположность перемещению элементов управления с помощью мыши. Будет немного больно, когда вы перережете пуповину мыши, но это единственный способ продвинуться вперед.   -  person Hans Passant    schedule 17.01.2015
comment
Хорошая точка зрения. Я не рассматривал сохранение. Ответ, предоставленный Гансом, делает один ящик с изображениями родителем другого, давая дочернему элементу прозрачность. Об остальном вам все равно придется позаботиться, как было предложено.   -  person OhBeWise    schedule 17.01.2015
comment
Всем спасибо, я вернусь, когда начну реализовывать математическую часть редактора. @HansPassant, этот шнур был разорван вчера, когда мне пришлось динамически отображать элементы управления в форме. :) Так как я начал использовать формы C # вчера (когда я начал этот проект), вместо того, чтобы спать на лекциях, я все еще немного свободен в терминах, таких как «краски». :)   -  person CodeBreaker    schedule 17.01.2015
comment
Может помочь, если вы посмотрите на уже существующий Paint.NET, чтобы оценить архитектуру и уровень сложности. Всегда полезно сначала взглянуть на чью-то работу, прежде чем пытаться заново изобрести велосипед. Вот ссылка: codeproject.com/Articles/449519/Developer-Tools -Paint-NET   -  person zmechanic    schedule 17.01.2015


Ответы (1)


Создание программы, похожей на Photoshop, — увлекательный проект.

На вашем пути будет много испытаний, и стоит немного подумать наперед.

Вот краткий и неполный список вещей, о которых следует помнить:

  • Рисовать и раскрашивать действия
  • Отменить, повторить, изменить
  • Несколько слоев
  • Масштабирование и прокрутка
  • Сохранение и печать

Так что получить фон в виде шахматной доски — это только начало большого пути.

Использование PictureBox в качестве основного холста — очень хороший выбор, так как его несколько слоев помогут. Вот фрагмент кода, который предоставит вам гибкий фон шахматной доски, который сохранит свой размер, даже когда вы масштабируете реальную графику:

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;
}

Загрузите изображение для тестирования, и вот что вы получите, слева нормально, справа увеличено:

введите здесь описание изображениявведите здесь описание изображения

Да, для сохранения этот фон надо убрать; как вы можете видеть в коде, передача size = 0 сделает это.

Что дальше? Позвольте мне дать вам несколько советов о том, как подходить к различным задачам сверху:

  • Прокрутка: Picturebox не может прокручивать. Вместо этого поместите его в Panel с AutoScroll = true и сделайте его настолько большим, насколько это необходимо.

  • Масштабирование: Играя с его Size и SizeMode, вы сможете увеличивать и уменьшать масштаб Image без проблем. BackgroundImage останется немасштабированным, как в Photoshop. Однако вам придется добавить еще немного кода, чтобы увеличить графику, которую вы рисуете поверх PB или слоев. Ключевым моментом здесь является масштабирование объекта Graphics с помощью Graphics.MultiplyTransform(Matrix).

  • Слои: Слои — это самая полезная функция в PhotoShop (и других качественных программах). Их можно достичь путем вложения прозрачных холстов для рисования. Можно использовать Panels, я предпочитаю Labels. Если каждый из них находится внутри расположенного под ним, а тот, что находится внизу, имеет PB в качестве Parent, все их содержимое будет показано вместе.

    • Don't use the Label directly but create a subclass to hold additional data and know-how!
    • Изменить их порядок не очень сложно, просто помните о вложенной структуре!
    • Скрытие слоя выполняется путем установки флага и проверки этого флага в действиях рисования.
    • Другие данные могут включать в себя имя, непрозрачность, возможно, цвет наложения.
    • Слои также должны отображаться в палитре слоев, лучше всего создать миниатюру и вставить пользовательский объект слоя в FlowLayoutPanel
  • Действия рисования: они всегда являются ключом к любому рисованию в WinForms. При использовании мыши для рисования каждое такое действие создает объект класса DrawAction, который вам нужно спроектировать, который содержит всю информацию, необходимую для фактического рисования, например:

    • Type (Rectangle, filledRectangle, Line, FreeHandLine (a series of Points), Text, etc.etc..)
    • Цвета
    • Точки
    • Ширина
    • Текст
    • Слой для рисования
    • может даже поворот

    Наряду с классом LayerCanvas класс DrawAction будет самым важным классом в проекте, поэтому над его дизайном стоит поработать!

    Только самый верхний слой будет получать события мыши. Поэтому вам нужно отслеживать, какой слой является активным, и добавлять действие в его список действий. Разумеется, активный слой также должен быть указан в палитре слоев.

  • Поскольку все рисунки хранятся в списках, реализовать неограниченное количество отмен и повторов очень просто. Чтобы обеспечить эффективное рисование и отмену, возможно, лучше всего использовать общий список действий и отдельный список для каждого слоя.

    • Undo and Redo are just matter of removing the last list element and pushing it onto a redo-stack.
    • Также возможно редактирование действий, включая изменение параметров, перемещение их вверх или вниз по списку действий или удаление одного из середины списка. Это помогает показать палитру действий, например F9 в PhotoShop.
    • Чтобы объединить два или более слоев вместе, вам нужно всего лишь объединить их списки действий.
    • Чтобы свести все слои в Image, вам нужно всего лишь нарисовать их не на их холсте, а в изображение. Для разницы рисования в элемент управления или в растровое изображение см. здесь! Здесь у нас есть PictureBox.Image как второй уровень структуры ПБ над Background.Image. (Третий — это поверхность Control, но с несколькими слоями сверху он нам на самом деле не нужен..)
  • Сохранение может быть выполнено либо с помощью Image.Save() после объединения всех слоев, либо после того, как вы выключили BackgroundImage, сказав PB нарисовать себя в Bitmap ( control.DrawToBitmap() ), который вы затем можете сохранить.

Развлекайся!

person TaW    schedule 17.01.2015
comment
Большое спасибо за длинный ответ. Прокрутка: я добавил tabControl, так как я хочу открыть несколько проектов, поэтому, когда пользователь добавляет новый файл, он создает pictureBox, добавляет в TabPage (AntoScroll = ture), а затем добавляет его в tabControl. Слои: Какая польза от использования меток вместо картинок, которые я планировал использовать? - person CodeBreaker; 17.01.2015
comment
Обычно я стараюсь делать вещи простыми, а PictureBox немного более мощный/дорогой; но, особенно если вы рисуете их изображения, вы можете сэкономить усилия при масштабировании. Но если вы рисуете на поверхности, это не имеет большого значения. - person TaW; 17.01.2015