Александр Климов - Программирование КПК и смартфонов на .NET Compact Framework
Нужно создать новый проект и разместить на форме какой-нибудь элемент управления, например кнопку. Кнопка не будет выполнять никаких функций. Она потребуется лишь для демонстрации технологии. Также надо добавить в проект изображение, которое будет использоваться в качестве фона для формы. В нашем примере картинка будет внедрена в программу как ресурс, хотя можно загрузить ее из обычного графического файла. Чтобы все работало так, как запланировано, необходимо переопределить метод OnPaint(). Новый код метода приведен в листинге 6.16.
Листинг 6.16protected override void OnPaint(PaintEventArgs e) {
// получим картинку из ресурсов Bitmap
backgroundImage = new Bitmap(Assembly.GetExecutingAssembly().
GetManifestResourceStream("BackgroundImageCS.sochicat.jpg"));
e.Graphics.DrawImage(backgroundImage, this.ClientRectangle,
new Rectangle(0, 0, backgroundImage.Width, backgroundImage.Height),
GraphicsUnit.Pixel);
}
После запуска программы можно будет увидеть, что форма имеет фоновый рисунок, а кнопка расположена поверх фона (рис. 6.3).
Рис. 6.3. Заполнение фона формы своим рисунком
Копирование рисунка
Библиотека .NET Compact Framework 1.0 не поддерживает метод System.Drawing.Image.Clone, позволяющий создать точную копию картинки. Это ограничение легко обходится с помощью создания собственных методов. Кроме того, можно расширить возможности метода и добавить функциональность, позволяющую копировать часть картинки. Соответствующий код приведен в листинге 6.17.
Листинг 6.17// Копируем всю картинку
protected Bitmap CopyBitmap(Bitmap source) {
return new Bitmap(source);
}
// Копируем часть картинки
protected Bitmap CopyBitmap(Bitmap source, Rectangle part) {
Bitmap bmp = new Bitmap(part.Width, part.Height);
Graphics g = Graphics.FromImage(bmp);
g.DrawImage(source, 0, 0, part, GraphicsUnit.Pixel);
g.Dispose();
return bmp;
}
private void button1_Click(object sender, EventArgs e) {
Graphics g = CreateGraphics();
Bitmap myBMP = new Bitmap(@"windowsbanner.gif");
// Половина ширины картинки
int left = myBMP.Size.Width / 2;
// Копируем всю картинку Bitmap
clone = CopyBitmap(myBMP);
// копируем левую часть картинки
Bitmap part =
CopyBitmap(myBMP, new Rectangle(0, 0, left, myBMP.Size.Height));
// Выводим три картинки по вертикали:
// источник, копию и копию левой части
int y = 10;
// картинка-источник
g.DrawImage(myBMP, 10, y);
y += myBMP.Height + 10;
// картинка-копия
g.DrawImage(clone, 10, y);
y += clone.Height + 10;
// копия левой части картинки
g.DrawImage(part, 10, y);
y += part.Height + 10;
g.Dispose();
}
private void button2_Click(object sender, EventArgs e) {
Graphics g = CreateGraphics();
Bitmap myBMP = new Bitmap(@"windowsbanner.gif");
g.Clear(Color.White);
int left = myBMP.Size.Width / 2; // Копия картинки
Bitmap clone = (Bitmap)myBMP.Clone();
int y = 10;
g.DrawImage(myBMP, 10, y);
y += myBMP.Height + 10;
g.DrawImage(clone, 10, y);
y += clone.Height + 10;
g.Dispose();
}
В этом примере создаются две перегруженные версии метода CopyImage. При помощи этого метода можно копировать картинку или ее часть. Для сравнения в примере было показано, как можно скопировать картинку с помощью метода Clone, доступного в .NET Compact Framework 2.0. Результат работы соответствующего приложения показан на рис. 6.4.
Рис. 6.4. Копирование картинки разными способами
Поддержка прозрачности
Библиотека .NET Compact Framework позволяет использовать прозрачный цвет, но при этом налагает определенные ограничения на эту возможность. Например, в библиотеке нет такого удобного метода, как MakeTransparent. Но разработчик может задать прозрачный цвет при помощи метода SetColorKey класса ImageAttributes. При этом разрешается использовать один и тот же цвет для минимального и максимального значений цветового ключа в версии метода ImageAttributes.SetColorKey(Color.Color).
ПРИМЕЧАНИЕВторая перегруженная версия метода ImageAttributes.SetColorKey(Color, Color, ColorAdjustType) в .NET Compact Framework не поддерживается.
Используя прозрачный цвет, можно добиться красивых результатов при наложении картинки на картинку. Этот механизм стоит продемонстрировать на конкретном примере.
Для тестового приложения были подготовлены две картинки. Первое изображение является фотографией моего кота, а во втором хранится небольшая табличка с его именем, сделанная за несколько секунд в стандартной программе Paint. При создании таблички фон был залит красным цветом, а для текстовой строки был выбран другой тон. Затем оба рисунка были добавлены в проект как ресурсы.
Чтобы продемонстрировать рассматриваемый эффект, надо расположить на форме две кнопки. При нажатии первой кнопки табличка будет накладываться на фотографию без изменений. При нажатии на вторую кнопку красный цвет сначала будет определен как прозрачный и только потом произойдет наложение изображений.
Основной код приложения приведен в листинге 6.18.
Листинг 6.18private void butAddImage_Click(object sender, EventArgs e) {
Graphics g = CreateGraphics();
// получим картинки из ресурсов
Bitmap imgCat = new Bitmap(Assembly.GetExecutingAssembly().
GetManifestResourceStream("TransparentCS.mycat.jpg"));
Bitmap imgName = new Bitmap(Assembly.GetExecutingAssembly().
GetManifestResourceStream("Transparent_CS.catname.bmp"));
g.DrawImage(imgCat, 0, 0,
new Rectangle(0, 0, imgCat.Width, imgCat.Height), GraphicsUnit.Pixel);
g.DrawImage(imgName, 50, 120,
new Rectangle(0, 0, imgName.Width.imgName.Height), GraphicsUnit.Pixel);
g.Dispose();
}
private void butImage2_Click(object sender, EventArgs e) {
Graphics g = CreateGraphics();
// получим картинки из ресурсов
Bitmap imgCat = new BitmapCAssembly.GetExecutingAssembly().
GetManifestResourceStream("Transparent_CS.mycat.jpg"));
Bitmap imgName = new Bitmap(Assembly.GetExecutingAssembly().
GetManifestResourceStream("Transparent_CS.catname.bmp"));
// Очистим экран
g.Clear(Color.White);
// Выводим первую картинку
g.DrawImage(imgCat, 0, 0,
new Rectangle(0, 0, imgCat.Width, imgCat.Height), GraphicsUnit.Pixel);
ImageAttributes attr = new ImageAttributes();
// Устанавливаем красный цвет как прозрачный
attr.SetColorKey(Color.Red, Color.Red);
// Выводим вторую картинку с установленными атрибутами
Rectangle dstRect = new Rectangle(50, 120, imgName.Width, imgName.Height);
g.DrawImage(imgName, dstRect, 0, 0,
imgName.Width, imgName.Height, GraphicsUnit.Pixel.attr);
g.Dispose();
}
ВНИМАНИЕHe забудьте импортировать пространство имен System.Drawing.Imaging при работе с этим примером.
Если просто наложить одну картинку на другую, то результат будет, мягко говоря, не очень красивым (рис. 6.5).
Рис. 6.5. Неудачный вариант наложения двух картинок
Если же воспользоваться методом SetColorKey для установки прозрачного цвета, то результат наложения двух изображений будет выглядеть достойно (рис. 6.6).
Рис. 6.6. Наложение картинки с использованием прозрачности
Округленные прямоугольники
Так как .NET Compact Framework не позволяет создавать округленные прямоугольники встроенными средствами, то необходимо самостоятельно реализовать эту задачу. В этом разделе будет рассматриваться решение, предложенное Алексом Яхниным (Alex Yakhnin) в его блоге blog.opennetcf.org/ayakhnin/. Для достижения заданного эффекта надо нарисовать серию линий, которые соединяют эллипсы, и закрасить внутреннюю область сплошным цветом (рис. 6.7).
Рис. 6.7. Создание прямоугольника со скругленным углами
Соответствующий код приведен в листинге 6.19.
Листинг 6.19public static void DrawRoundedRectangle(Graphics g, Pen p, Color backColor,
Rectangle rc, Size size) {
Point[] points = new Point[8];
// подготовим точки для фигуры
points[0].X = rc.Left + size.Width / 2;
points[0].Y = rc.Top + 1;
points[1].X = rc.Right - size.Width / 2;
points[1].Y = rc.Top + 1;
points[2].X = rc.Right;
points[2].Y = rc.Top + size.Height / 2;
points[3].X = rc.Right;
points[3].Y = rc.Bottom - size.Height / 2;
points[4].X = rc.Right - size.Width / 2;
points[4].Y = rc.Bottom;
points[5].X = rc.Left + size.Width / 2;
points[5].Y = rc.Bottom;
points[6].X = rc.Left + 1;
points[6].Y = rc.Bottom - size.Height / 2;
points[7].X = rc.Left + 1;
points[7].Y = rc.Top + size.Height / 2;
// приготовим кисть для фона
Brush fillBrush = new SolidBrush(backColor);
// рисуем отрезки и круги для округленного прямоугольника