5

I'm making a Blackjack game for a project in college (semester-long) and I've hit a road block that I can't seem to get over.

I'm trying to load the card images so they can be displayed onscreen, but I've been having very little luck in doing so. I've got absolute references down; I can load from those, but any attempt to load from a relative path fails. The project must be standalone; I can't instruct my professor to copy these images onto the root.

#if FROMDISK
        Uri myUri = new Uri(@"C:\cards\" + getFilename(r, s, "png"), UriKind.Absolute);
        PngBitmapDecoder decoder2 = new PngBitmapDecoder(myUri, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
        BitmapSource bmp = decoder2.Frames[0];
#else
        System.Reflection.Assembly myAssembly = System.Reflection.Assembly.GetExecutingAssembly();
        Stream myStream = myAssembly.GetManifestResourceStream("Blackjack." + getFilename(r, s, "png"));
        BitmapImage bmp = new BitmapImage();
        bmp.StreamSource = myStream;
#endif
        // Draw the Image
        im.Source = bmp;
        im.Stretch = Stretch.Uniform;
        im.Width = CARD_WIDTH;

(Context)

Sean Allred
  • 3,558
  • 3
  • 32
  • 71

3 Answers3

7

You can use:

Uri uri = new Uri(@"FolderName\FileName.png",UriKind.Relative);
PngBitmapDecoder decoder2 = new PngBitmapDecoder(uri, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);

Remember to set the properties for the image file to (otherwise the compiler will skip them) you can look the bin/debug folder after build and verify that the file is where it should be:

  • Build action: content
  • Copy to output directory: Copy always

Another option is to make the file an embedded resource then you can access it like this:

Bitmap bitmap = Properties.Resources.FileName;
Community
  • 1
  • 1
Johan Larsson
  • 17,112
  • 9
  • 74
  • 88
  • Which file(s) should I set those properties for? Setting them for the code file seems to be the wrong move (I'm going to be honest: I have no idea what they really do) – Sean Allred Oct 25 '12 at 23:33
  • I'm not sure why SO didn't notify me of all of this, but I'll try this out when I get home! – Sean Allred Nov 06 '12 at 00:08
3

I like to declare images as resources in my XAML. I will assume that you can still play around with the code structure at this point, and hopefully there aren't too many new concepts for you. Here's how I do it:

Start y creating a folder in your project called "Images". Add the images of your cards by drag and dropping them onto the folder in Visual Studio. Make sure their "Build Action" is set to Resource.

Create a new "Resource Dictionary" by pressing CTRL-SHIFT-A. Name it CardImages.xaml.

Link this file in App.xaml like this (showing how to link multiple XAML files at once, but for this of course remove the "AnyDictionary" line!)

App.XAML:

<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="Controls/CardImages.xaml" />
            <ResourceDictionary Source="Controls/AnyDictionaryYouWant.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>

Add this code to CardImages.xaml. Rename "MyBlackJackAssembly" to the assembly name of your proejct.

<Style TargetType="Image">
    <Setter Property="RenderOptions.BitmapScalingMode" Value="HighQuality" />
</Style>

<DataTemplate x:Key="Spade1">
    <Image Source="MyBlackJackAssembly;component/Images/Spade1.png" />
</DataTemplate>

<DataTemplate x:Key="Spade2">
    <Image Source="MyBlackJackAssembly;component/Images/Spade2.png" />
</DataTemplate>

Then, you can locate them in your code like this:

Label label = new Label();
label.ContentTemplate = (DataTemplate)label.FindResource("Spade1");

This will get you a WPF Label object that should show your card. This technique works with anything that supports ContentTemplate. You can then add your Label to a grid on your UI, I'm not sure how you display your cards on screen.

For a blackjack application, I would probably create a UserControl called "Card" in order to be able to generate it kind of like this. This encapsulates the "card generation" logic into its own Control so the rest of the code can just focus on dealing the cards.

XAML:

<myControls:CardImage Kind="Spades" Digit="1" />

Or like this in c#:

CardImage aCard = new CardImage();
aCard.Kind = CardImage.Kinds.Spades; //enum
aCard.Digit = 1;
Joe
  • 2,496
  • 1
  • 22
  • 30
  • 1
    I'm not sure why SO didn't notify me of all of this, but I'd just like to say I'm extraordinarily excited to get home and try this! C# is a crazy convenient language. – Sean Allred Nov 06 '12 at 00:08
1

The way I'm loading some background images that are imported in the project's resources:

this.staticBg.Source = new BitmapImage(
    new Uri(@"/Project;component/Images/" + ((App)App.Current).bgImage
                                          + ".jpg", UriKind.Relative));

Where "Project" is project name. So basically you should add images to resources and call them with relative uri.

Sean Allred
  • 3,558
  • 3
  • 32
  • 71
Clone
  • 535
  • 1
  • 6
  • 14
  • I modified my code thusly: `im.Source = new BitmapImage(new Uri(@"/Project;component/Images/" + getFilename(r, s, "png"), UriKind.Relative))` - would this be correct? because it doesn't seem to be working. It isn't throwing an error, just nothing is showing up. Is 'Images' some folder you made? – Sean Allred Oct 25 '12 at 23:15
  • @vermiculus To keep the images with your application (and eliminate the need of your #FROMDISK maybe?), you have to drag the image into your project in Visual Studio. Then you make sure their Build Action is set to "Resource" (but usually this is already OK). Then you can reference it like Clone says, or you can try a more "WPF" approach by creating a UserControl object that act as a visual object for your window. – Joe Oct 26 '12 at 00:24
  • Hi, I created Images folder, by right-clicking on the project name and selecting Add->New Folder. Then imported the actual images by right-clicking the images folder and selecting Add->Existing Item. Build action is set to Content, and Copy To Output to Copy Always (it can also be Copy If Newer, if you want to speed up the build). – Clone Oct 26 '12 at 06:30