Главная » Разработка для Windows Phone 7 » Работа с пикселами Windows Phone 7 – Свойство Pixels класса WritableBitmap

0

Свойство Pixels класса WritableBitmap – это массив объектов типа int, т.е. каждый пиксел включает 32 бита. Само свойство Pixels является свойством только для чтения, таким образом, мы не можем заменить массив целиком, но можем задавать и возвращать элементы этого массива.

Растровое изображение – это двухмерный массив пикселов. Свойство Pixels класса WriteableBitmap – это одномерный массив значений типа int. В массиве Pixels пикселы растрового изображения хранятся последовательно, начиная с верхней строки и вниз, двигаясь по строкам слева направо. Количество элементов в массиве равно произведению ширины и высоты растрового изображения в пикселах.

Если bm – объект WriteableBitmap, тогда количество элементов в свойстве Pixels равно bm.PixelWidth * bm.PixelHeight. Предположим, требуется выполнить доступ к пикселу в столбце x, где значения x лежат в диапазоне от 0 до bm.PixelWidth – 1, и строке y, где значения y лежат в диапазоне от 0 до bm. PixelHeight- 1. Свойство Pixels индексируется следующим образом:

bm.Pixels[y * bm.PixelWidth + x]

Silverlight for Windows Phone поддерживает только один формат пикселов, который иногда обозначают как PARGB32. Позвольте мне расшифровать это кодовое название. Начнем с конца.

«32» в конце названия формата означает 32 бита или 4 байта. Это размер одного пиксела. Буквы ARGB указывают на то, что байт Альфа-канала (непрозрачность) расположен в старших 8 битах 32-разрядного целого. За ним следует байт красного канала (Red), байт зеленого (Green) и байт синего (Blue), который занимает младшие 8 битов целого.

Если A, R, G и B типа byte, 32-разрядное целое значение пиксела можно составить следующим образом:

int pixel = A << 24 | R << 16 | G << 8 | B

Смещенные значения, неявно преобразованные в значения типа int, объединяются посредством оператора C# побитовое ИЛИ. Получить компоненты фактического значения пиксела можно следующим образом:

byte A = (byte)(pixel & 0xFF0 0 0 0 0 0 >> 24); byte R = (byte)(pixel & 0x00FF0000 >> 16); byte G = (byte)(pixel & 0x0000FF00 >> 8); byte B = (byte)(pixel & 0x000000FF);

Если байт альфа-канала содержит 255, пиксел непрозрачный. Значение 0 соответствует полностью прозрачному пикселу. Промежуточные значения указывают на промежуточные уровни прозрачности.

В формате пикселов PARGB32 Р означает «premultiplied», т.е. «предварительно умножены». Это говорит о том, что если значение альфа-канала отлично от 255, значения красного, зеленого и синего уже приведены в соответствие заданной прозрачности.

Попробуем разобраться с этой концепцией на примере одного пиксела. Предположим, мы решили задать пикселу следующий цвет:

Color.FromArgb(12 8, 0, 0, 255)

Это соответствует синему с 50% прозрачностью. При формировании визуального представления этого пиксела на поверхности, имеющей определенный фон, его цвет должен комбинироваться с имеющимися цветами поверхности. При отрисовке на черном фоне результирующим RGB-цветом будет (0, 0, 128). Это что-то среднее между синим и черным. При отрисовке на белом фоне результирующим цветом будет (127, 127, 255). Каждый из трех компонентов результирующего цвета является средним арифметическим между значениями пиксела и поверхности.

При любом другом значении прозрачности, отличном от 50%, результирующий цвет является средневзвешенным значением от значений исходного пиксела и поверхности. Подстрочные индексы переменных в следующих формулах указывают на «результат» (result) формирования визуального представления частично прозрачного пиксела «источника» (source) на существующей «поверхности» (surface):

Rresult = [(255 — Asource) X R Surface + A source X Rsurface]  255

Gresult = [(255 Asource) X G surface + A source X Gsurface]   255

Bresult= [(255- Asource) X B surface +A source X И surface]  255

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

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

цветов на значение альфа-канала. Это предварительное умножение для каждого компонента выполняется следующим образом:

PRsource = (A source *R source)  255

И аналогично для зеленого и синего. Это позволяет вдвое сократить количество операций умножения в результирующих уравнениях для формирования визуального представления растрового изображения:

Rresult = [(255 –  A source) X R surf асе]   2 5 5 + PR source

Когда бы мы ни работали со свойством Pixels объекта WriteableBitmap, мы всегда имеем дело с предварительно умноженными значениями. Например, пикселу растрового изображения необходимо задать RGB-значение цвета (40, 60, 255), но при этом значение альфа-канала равно 192. ARGB-значение в растровом изображении будет (192, 30, 45, 192). Каждое из составляющих значений цвета было умножено на 192/255 или примерно на 0,75.

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

При работе с ARGB-значениями цвета без предварительного умножения на альфа-канал различают «прозрачный черный», которому соответствует ARGB-значение (0, 0, 0, 0), и «прозрачный белый», которому соответствует ARGB-значение (0, 255, 255, 255). С предварительным умножением это различие исчезает, потому что прозрачный белый тоже будет соответствовать (0, 0, 0, 0).

Когда WriteableBitmap создается впервые, все пикселы имеют нулевое значение, что можно трактовать как «прозрачный черный», или «прозрачный белый», или «прозрачный серо- буро-малиновый».

Прямая запись в массив Pixels объекта WriteableBitmap позволяет создавать изображения любого типа.

С помощью сравнительно простых алгоритмов можно создавать стили кистей, которые не обеспечиваются стандартными производными от Brush. Область содержимого проекта CircularGradient (Круговой градиент) включает только один элемент Image, предназначенный для размещения в нем растрового изображения:

Проект Silverlight: CircularGradient Файл: MainPage.xaml (фрагмент)

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <Image Name="img"

HorizontalAlignment="Center" VerticalAlignment="Center" />

</Grid>

В файле выделенного кода MainPage значение радиуса выбрано довольно произвольно, и для WriteableBitmap задан квадрат со стороной, равной двум радиусам. Два цикла for для x и y обеспечивают перебор всех пикселов этой растровой матрицы:

Проект Silverlight: CircularGradient Файл: MainPage.xaml.cs (фрагмент)

public partial class MainPage : PhoneApplicationPage {

const int RADIUS = 200;

public MainPage() {

InitializeComponent();

WriteableBitmap writeableBitmap = new WriteableBitmap(2 * RADIUS, 2 *

RADIUS);

for (int y = 0; y < writeableBitmap.PixelWidth; y++)

for (int x = 0; x < writeableBitmap.PixelHeight; x++) {

if (Math.Sqrt(Math.Pow(x – RADIUS, 2) + Math.Pow(y – RADIUS, 2)) <

RADIUS)

{

double angle = Math.Atan2(y – RADIUS, x – RADIUS); byte R = (byte)(255 * Math.Abs(angle) / Math.PI); byte B = (byte)(255 – R); int color = 255 << 24 | R << 16 | B;

writeableBitmap.Pixels[y * writeableBitmap.PixelWidth + x] =

color;

}

}

writeableBitmap.Invalidate(); img.Source = writeableBitmap;

}

}

Центром WriteableBitmap является точка с координатами (200, 200). Вложенные циклы for начинаются с пропуска каждого пиксела, который отстоит от центра более чем на 200 пикселов. В этом квадратном растровом изображении непрозрачными будут только пикселы, принадлежащие кругу.

Линия, соединяющая центральную точку с любым пикселом растрового изображения, образует угол с горизонтальной осью. Этот угол вычисляется методом Math.Atan2. Затем на основании значения этого угла задаются значения переменным R и B, значение цвета формируется и сохраняется в массиве Pixels. Вызов Invalidate сопоставляет фактическое растровое изображение с этими пикселами. После этого растровое изображение задается как значение свойства Source элемента Image:

Источник: Чарльз Петзольд, Программируем Windows Phone 7, Microsoft Press, © 2011.

По теме:

  • Комментарии