//----------------------------------------------------------------------------- // SavingImagesGame.cs // // Microsoft XNA Community Game Platform // Copyright (C) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- using System; using System.IO; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Input.Touch; using Microsoft.Xna.Framework.Media; namespace SavingEmbeddedImages { /// /// SavingEmbeddedImages shows two ways of transferring content from a game project to /// the Windows Phone 7 Media Library: /// /// 1. Loading an image texture from the game's content project, converting the /// image to a jpeg, and saving it to the media library. /// /// 2. Obtaining an image stream from the game project files and saving the stream /// to the media library /// public class SavingImagesGame : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; SpriteFont mainFont; SpriteFont detailFont; Texture2D backgroundImage; // This image will be loaded from the game project Texture2D gameProjectImage; // This image will be loaded from the content project Texture2D contentProjectImage; // Bounding rectangles are used for image display and hit-testing. // These coordinates were chosen to look nice, no other special reason. Rectangle gameProjectImageBounds = new Rectangle(20, 20, 200, 333); Rectangle contentProjectImageBounds = new Rectangle(260, 20, 200, 333); // Simple flag to ignore UI input when system dialogs are animating. bool imageSaveInProgress = false; /// /// Set up the game to run full screen and full resolution. /// public SavingImagesGame() { graphics = new GraphicsDeviceManager(this); graphics.PreferredBackBufferWidth = 480; graphics.PreferredBackBufferHeight = 800; graphics.IsFullScreen = true; Content.RootDirectory = "Content"; // Frame rate is 30 fps by default for Windows Phone. TargetElapsedTime = TimeSpan.FromTicks(333333); } /// /// Perform pre-game initialization /// protected override void Initialize() { base.Initialize(); // enable tap gestures only for this sample TouchPanel.EnabledGestures = GestureType.Tap; } /// /// Load UI content and fonts. Also create a drawable texture from both image types. /// protected override void LoadContent() { // Create a new SpriteBatch, which can be used to draw textures. spriteBatch = new SpriteBatch(GraphicsDevice); // Load the background image. backgroundImage = Content.Load("GameBackground"); // load the fonts mainFont = Content.Load("mainFont"); detailFont = Content.Load("detailFont"); // Load the embedded image from the game project using TitleContainer // and constructing a Texture2D from the resulting stream object. // Note that the image properties are set to "Copy if newer" in the // game project. using (Stream gameProjectImageStream = TitleContainer.OpenStream("GameProjectImage.jpg")) { gameProjectImage = Texture2D.FromStream(GraphicsDevice, gameProjectImageStream); } // Load the embedded image from the content project using the content loader. contentProjectImage = Content.Load("ContentProjectImage"); } /// /// Check for the back button to exit the app, and see if a touch occurred /// on one of the images. /// protected override void Update(GameTime gameTime) { // Allows the game to exit if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); // check for touch input while (TouchPanel.IsGestureAvailable) { GestureSample gesture = TouchPanel.ReadGesture(); // The text input dialog can allow input to occur between when it closes and when the // callback occurs, so the game guards against processing input in this state with a // simple flag. if (gesture.GestureType == GestureType.Tap && !imageSaveInProgress) { Point tapLocation = new Point((int)gesture.Position.X, (int)gesture.Position.Y); // An image touch triggersGuide.BeginShowKeyboardInput to receive // a filename. A hit-test determines which image was touched, and // the callback is different depending on the source of the image. if (gameProjectImageBounds.Contains(tapLocation)) { imageSaveInProgress = true; Guide.BeginShowKeyboardInput( 0, "Save Picture", "Enter a filename for your image", "gameProjectImage", SaveGameProjectImageCallback, null); } if (contentProjectImageBounds.Contains(tapLocation)) { imageSaveInProgress = true; Guide.BeginShowKeyboardInput( 0, "Save Picture", "Enter a filename for your image", "contentProjectImage", SaveContentProjectImageCallback, null); } } } base.Update(gameTime); } /// /// Render the UI. /// protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); spriteBatch.Begin(); spriteBatch.Draw(backgroundImage, new Vector2(0, 0), Color.White); spriteBatch.Draw(gameProjectImage, gameProjectImageBounds, null, Color.White); spriteBatch.DrawString( detailFont, "game project image", new Vector2(gameProjectImageBounds.X, gameProjectImageBounds.Y + gameProjectImageBounds.Height), Color.White); spriteBatch.Draw(contentProjectImage, contentProjectImageBounds, null, Color.White); spriteBatch.DrawString( detailFont, "content project image", new Vector2(contentProjectImageBounds.X, contentProjectImageBounds.Y + contentProjectImageBounds.Height), Color.White); spriteBatch.DrawString(mainFont, "Tap an image to save it\nto your media library.", new Vector2(40,500), Color.White); spriteBatch.End(); base.Draw(gameTime); } /// /// Utility function to save a stream to the media library. Media Library access won't /// work if the Zune desktop software is running. /// protected void SaveStreamToMediaLibrary(string filename, Stream stream) { MediaLibrary library = new MediaLibrary(); string messageBoxTitle; string messageBoxContent; string[] buttons = { "OK" }; MessageBoxIcon messageBoxIcon; try { library.SavePicture(filename, stream); messageBoxTitle = "Image saved."; messageBoxContent = filename + " successfully added to your Media Library."; messageBoxIcon = MessageBoxIcon.None; } catch (InvalidOperationException) { // The most likely reason for failure is that the Zune desktop software is running. // This prevents the phone from saving content to the device's media library. messageBoxTitle = "Unable to save image."; messageBoxContent = "The image could not be saved to the Media Library. One reason might be that the phone is tethered to a PC with the Zune software running."; // the phone doesn't display an icon, but specifying MessageBoxIcon.Error causes a warning sound effect to be played messageBoxIcon = MessageBoxIcon.Error; } IAsyncResult messageResult = Guide.BeginShowMessageBox( messageBoxTitle, messageBoxContent, buttons, 0, messageBoxIcon, null, null); Guide.EndShowMessageBox(messageResult); imageSaveInProgress = false; } /// /// Called when the user has picked a filename for the GameProject image. /// protected void SaveGameProjectImageCallback(IAsyncResult result) { string filename = Guide.EndShowKeyboardInput(result); if (!string.IsNullOrEmpty(filename)) { // Both content images are loaded as textures for display, and could be // saved with Texture2D.SaveAsJpeg(), but if you need to go from // an image embedded in the .xap, an alternative approach is // to open a TitleContainer stream, and save it to the media library. using (Stream stream = TitleContainer.OpenStream("GameProjectImage.jpg")) { SaveStreamToMediaLibrary(filename, stream); } } else { imageSaveInProgress = false; } } /// /// Called when the user has picked a filename for the ContentProject image. /// protected void SaveContentProjectImageCallback(IAsyncResult result) { string filename = Guide.EndShowKeyboardInput(result); if (!string.IsNullOrEmpty(filename)) { /// Write a Texture2D to a stream and then save the stream to the media library. // The media library expects a Jpeg image, so make sure it gets the input type it wants. using (MemoryStream stream = new MemoryStream()) { contentProjectImage.SaveAsJpeg(stream, contentProjectImage.Width, contentProjectImage.Height); // Reset the stream position after writing to it. stream.Seek(0, 0); SaveStreamToMediaLibrary(filename, stream); } } else { imageSaveInProgress = false; } } } }