Главная » Разработка для Windows Phone 7 » Сохранение в библиотеку изображений Windows Phone 7

0

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

Но наиболее ценной возможностью для пользователя является сохранение растрового изображения в библиотеке изображений телефона. Специально для этой цели предусмотрена отдельная папка (или «альбом», как принято говорить) под именем «Saved Pictures». В библиотеке изображений пользователь может просматривать получившиеся растровые изображения, отсылать их по электронной почте или в составе текстовых сообщений. Также изображения из библиотеки переносятся на компьютер при обычной синхронизации, после чего могут быть распечатаны.

Доступ к библиотеке изображений обеспечивается посредством классов библиотек XNA, но они могут использоваться из приложений на Silverlight. Для этого потребуется лишь указать ссылку на библиотеку Microsoft.Xna.Framework и с помощью директивы using подключить пространство имен Microsoft.Xna.Framework.Media.

В приложении создается экземпляр класса MediaLibrary. Его свойство SavedPictures (Сохраненные изображения) возвращает коллекцию PictureCollection. Для каждого элемента, хранящегося в настоящее время в альбоме Saved Pictures, в коллекции PictureCollection имеется соответствующий объект Picture. Пользователь может работать с ними посредством их имен.

Класс MediaLibrary также включает метод SavePicture, который принимает два обязательных параметра: имя файла и объект Stream, ссылающийся на растровое изображение в формате JPEG. Как правило, объект Stream типа MemoryStream, содержимое которого создано путем вызова метода расширения SaveJpeg объекта WriteableBitmap.

Приложение Monochromize (Создание черно-белого изображения) позволяет пользователю выбирать изображение из библиотеки изображений. Когда приложение получает фотографию в виде объекта WriteableBitmap, оно выполняет доступ к его свойству Pixels и преобразовывает это изображение в монохромное изображение. По нажатию кнопки Save выполняется переход к странице, на которой пользователь может ввести имя файла и нажать кнопку OK. При возвращении назад к приложению черно-белое растровое изображение сохраняется в библиотеку изображений под заданным именем.

Страница приложения Monochromize, на которой пользователь может ввести имя файла – это эквивалент Windows Phone 7 традиционному диалоговому окну для сохранения файла, поэтому я назвал ее SaveFileDialog (Диалоговое окно для сохранения файла). Этот класс является производным от PhoneApplicationPage и входит в состав библиотеки Petzold.Phone.Silverlight.

Для возвращения имени файла в конкретное приложение, использующее страницу SaveFileDialog, я применил несколько иную стратегию. Когда пользователь нажимает кнопку «save» или «cancel», SaveFileDialog вызывает метод GoBack объекта NavigationService, как обычно, но при последующем выполнении перегруженного метода OnNavigatedFrom он делает попытку вызвать метод главной страницы приложения SaveFileDialogCompleted (Работа с диалоговым окном для сохранения файла завершена). Поэтому любая страница, выполняющая переход к SaveFileDialog, должна также реализовывать следующий интерфейс:

Проект Silverlight: Petzold.Phone.Silverlight Файл: ISaveFileDialogCompleted.cs

namespace Petzold.Phone.Silverlight {

public interface ISaveFileDialogCompleted {

void SaveFileDialogCompleted(bool okPressed, string filename);

}

}

Область содержимого страницы SaveFileDialog включает традиционный TextBox с двумя кнопками, обозначенными надписями «save» и «cancel»:

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

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

<TextBlock Text="file name" /> <TextBox Name="txtbox"

TextChanged="OnTextBoxTextChanged" />

<Grid>

<Grid.ColumnDefinitions>

<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions>

<Button Name="saveButton" Content="save" Grid.Column="0" IsEnabled="False" Click="OnSaveButtonClick" />

<Button Content="cancel" Grid.Column="2"

Click="OnCancelButtonClick" />

</Grid> </StackPanel> </Grid>

В файле выделенного кода также определен открытый метод SetTitle (Задать заголовок). Приложение, использующее SaveFileDialog, может вызвать этот метод и задать заголовок страницы соответственно имени приложения:

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

public partial class SaveFileDialog : PhoneApplicationPage {

PhoneApplicationService appService = PhoneApplicationService.Current; bool okPressed; string filename;

public SaveFileDialog()

InitializeComponent();

public void SetTitle(string appTitle) ApplicationTitle.Text = appTitle;

void OnTextBoxTextChanged(object sender, TextChangedEventArgs args) saveButton.IsEnabled = txtbox.Text.Length > 0;

void OnSaveButtonClick(object sender, RoutedEventArgs args) {

okPressed = true;

filename = txtbox.Text;

this.NavigationService.GoBack();

}

void OnCancelButtonClick(object sender, RoutedEventArgs args) {

okPressed = false; this.NavigationService.GoBack();

}

}

Также обратите внимание, что кнопка «save» неактивна до тех пор, пока в TextBox не будет введен хотя бы один символ.

Перегруженные методы навигации выполняют несколько задач. Метод OnNavigatedTo проверяет, содержит ли строка запроса имя исходного файла. (Приложение Monochromize не обеспечивает этой проверки, но она реализована в приложении, которое будет рассмотрено далее в данной главе.) Эти методы также обрабатывают захоронение, сохраняя заголовок приложения и любое имя файла, введенное пользователем:

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

protected override void OnNavigatedTo(NavigationEventArgs args) {

if (appService.State.ContainsKey("filename"))

txtbox.Text = appService.State["filename"] as string;

if (appService.State.ContainsKey("apptitle"))

ApplicationTitle.Text = appService.State["apptitle"] as string;

if (this.NavigationContext.QueryString.ContainsKey("FileName"))

txtbox.Text = this.NavigationContext.QueryString["FileName"];

base.OnNavigatedTo(args);

}

protected override void OnNavigatedFrom(NavigationEventArgs args) {

if (!String.IsNullOrEmpty(txtbox.Text))

appService.State["filename"] = txtbox.Text;

appService.State["apptitle"] = ApplicationTitle.Text;

if (args.Content is ISaveFileDialogCompleted)

(args.Content as ISaveFileDialogCompleted).

SaveFileDialogCompleted(okPressed, filename);

base.OnNavigatedFrom(args);

}

Самые важные операции описаны в конце метода OnNavigatedFrom. Здесь он проверяет, реализует ли страница, к которой выполняется переход, интерфейс ISaveFileDialogCompleted; и если да, вызывает метод SaveFileDialogCompleted этой страницы.

Описанная в XAML-файле область содержимого приложения Monochromize включает только пустой элемент Image:

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

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

<Image Name="img" /> </Grid>

ApplicationBar включает две кнопки для загрузки и сохранения: Проект Silverlight: Monochromize Файл: MainPage.xaml (фрагмент)

<phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar>

<shell:ApplicationBarIconButton x:Name="appbarLoadButton"

IconUri="/Images/appbar.folder.rest.png" Text="load"

Click="OnAppbarLoadClick" />

<shell:ApplicationBarIconButton x:Name="appbarSaveButton"

IconUri="/Images/appbar.save.rest.png" Text="save" IsEnabled="False" Click="OnAppbarSaveClick" />

</shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar>

В файле выделенного кода всего несколько полей, и только одно из них действительно необходимо. Это PhotoChooserTask. Поле PhoneApplicationService используется исключительно для удобства. После того как приложение создает объект WriteableBitmap, он также сохраняется Source как свойство элемента Image.

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

public partial class MainPage : PhoneApplicationPage, ISaveFileDialogCompleted {

PhoneApplicationService appService = PhoneApplicationService.Current; PhotoChooserTask photoChooser = new PhotoChooserTask(); WriteableBitmap writeableBitmap;

public MainPage() {

InitializeComponent();

appbarLoadButton = this.ApplicationBar.Buttons[0] as ApplicationBarIconButton;

appbarSaveButton = this.ApplicationBar.Buttons[1] as ApplicationBarIconButton;

photoChooser.Completed += OnPhotoChooserCompleted;

}

}

Обратите внимание, что этот класс реализует интерфейс ISaveFileDialogCompleted.

По щелчку кнопки «load» запускается PhotoChooserTask. По завершению его выполнения обработчик события Completed создает объект WriteableBitmap и изменяет все члены его массива Pixels, применяя стандартные взвешенные значения к значениям красного, зеленого и синего каналов.

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

void OnAppbarLoadClick(object sender, EventArgs args) {

appbarSaveButton.IsEnabled = false; photoChooser.Show();

}

void OnPhotoChooserCompleted(object sender, PhotoResult args) {

if (args.Error == null && args.ChosenPhoto != null) {

BitmapImage bitmapImage = new BitmapImage(); bitmapImage.SetSource(args.ChosenPhoto); writeableBitmap = new WriteableBitmap(bitmapImage);

// Преобразование в черно-белое изображение

for (int pixel = 0; pixel < writeableBitmap.Pixels.Length; pixel++) {

int color = writeableBitmap.Pixels[pixel];

byte A = (byte)(color & 0xFF0 0 0 0 0 0 >> 24);

byte R = (byte)(color & 0x00FF0000 >> 16);

byte G = (byte)(color & 0x0000FF00 >> 8);

byte B = (byte)(color & 0x000000FF);

byte gray = (byte)(0.30 * R + 0.59 * G + 0.11 * B);

color = (A << 24) | (gray << 16) | (gray << 8) | gray; writeableBitmap.Pixels[pixel] = color;

}

img.Source = writeableBitmap; appbarSaveButton.IsEnabled = true;

}

}

По нажатию кнопки сохранить выполняется переход на страницу SaveFileDialog.xaml из библиотеки Petzold.Phone.Silverlight. Как мы только что видели, класс SaveFileDialog

Черно-белый WriteableBitmap задается как значение свойства Source элемента Image, после чего активируется кнопка для сохранения этого изображения.

обрабатывает свой перегруженный OnNavigatedFrom, вызывая метод SaveFileDialogCompleted класса, к которому выполняется переход:

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

void OnAppbarSaveClick(object sender, EventArgs args) {

this.NavigationService.Navigate(

new Uri("/Petzold.Phone.Silverlight;component/SaveFileDialog.xaml", UriKind.Relative));

}

public void SaveFileDialogCompleted(bool okPressed, string filename) {

if (okPressed) {

MemoryStream memoryStream = new MemoryStream();

writeableBitmap.SaveJpeg(memoryStream, writeableBitmap.PixelWidth,

writeableBitmap.PixelHeight, 0, 75);

memoryStream.Position = 0;

MediaLibrary mediaLib = new MediaLibrary(); mediaLib.SavePicture(filename, memoryStream);

}

}

При записи растрового изображения в библиотеку изображений метод SaveFileDialogCompleted использует имя файла, веденное пользователем. Сохранение изображения выполняется в два этапа: сначала метод SaveJpeg записывает WriteableBitmap в MemoryStream в формате JPEG; после этого свойство Position объекта MemoryStream сбрасывается в исходное значение, и поток сохраняется в библиотеку изображений.

Приложение Monochromize также обрабатывает захоронение. Метод OnNavigatedFrom использует метод расширения SaveJpeg для записи в объект MemoryStream и затем сохраняет массив byte. Этот метод также отвечает за вызов метода SetTitle страницы SaveFileDialog в случае перехода на нее:

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

protected override void OnNavigatedFrom(NavigationEventArgs args) {

if (writeableBitmap != null) {

MemoryStream stream = new MemoryStream();

writeableBitmap.SaveJpeg(stream, writeableBitmap.PixelWidth,

writeableBitmap.PixelHeight, 0, 75); appService.State["jpegBits"] = stream.GetBuffer();

}

if (args.Content is SaveFileDialog) {

SaveFileDialog page = args.Content as SaveFileDialog; page.SetTitle(ApplicationTitle.Text);

}

base.OnNavigatedFrom(args);

}

Метод OnNavigatedTo отвечает за реактивацию элементов после захоронения. Массив byte преобразовывается в WriteableBitmap, и активируется кнопка для сохранения:

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

protected override void OnNavigatedTo(NavigationEventArgs args) {

if (appService.State.ContainsKey("jpegBits")) {

byte[] bitmapBits = (byte[])appService.State["jpegBits"]; MemoryStream stream = new MemoryStream(bitmapBits); BitmapImage bitmapImage = new BitmapImage(); bitmapImage.SetSource(stream);

writeableBitmap = new WriteableBitmap(bitmapImage); img.Source = writeableBitmap; appbarSaveButton.IsEnabled = true;

}

base.OnNavigatedTo(args);

}

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

По теме:

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