QR codes genereren met Google Infographics

Google heeft een heleboel leuke grafieken in de aanbieding. Deze zijn gratis te gebruiken, ondersteunen vele browsers en er zijn geen extra plugins nodig. Meer informatie is te vinden op: https://developers.google.com/chart/?hl=nl-NL

Tussen al deze goodies zitten ook de InfoGraphics. Hoewel dit op de site als “Deprecated ” staat, zitten hier nog wel enkele juweeltjes in.

Zo is er nog steeds QR code ondersteuning in:  https://google-developers.appspot.com/chart/infographics/docs/qr_codes

Een aanroep voor een QR geeft via een ‘fat url’ gewoon een png terug. Voor de bouw van een web is het dus erg eenvoudig om een QR code te tonen:

<img src="http://chart.apis.google.com/chart?cht=qr&chs=200x200&chl=http://blog.vandevelde-online.com"
alt="My favorite blog" />

Dit geeft in een website:

Er kan gevarieerd worden in grootte, de mate van fouttollerantie en encoding.

De output van zo’n aanroep is dus ook direct in een winform picturebox te plaatsen:

pictureBox1.Load(@<a href="http://chart.apis.google.com/chart?cht=qr&chs=200x200&chl=http://blog.vandevelde-online.com">http://chart.apis.google.com/chart?cht=qr&chs=200x200&chl=http://blog.vandevelde-online.com</a>);

Of als je het iets uitdagender wilt zien dan gebruik je de volgende aanroep:

using (var webClient = new WebClient())
{
  using (var stream = webClient.OpenRead(
     @<a href="http://chart.apis.google.com/chart?cht=qr&chs=200x200
               &chl=http://www.cognation.net/profile">http://chart.apis.
               google.com/chart?cht=qr&chs=200x200&chl=
               http://blog.vandevelde-online.com</a>))
  {
    var bitmap = Bitmap.FromStream(stream);
    pictureBox1.Image = bitmap;
  }
}

Dit resulteert beiden in de dezelfde output:

De InfoGraphics sectie bevat dus ook nog andere leuke en bruikbare plaatjes zoals bv. formules, pins, tekstballonnen, sticky notes, en vlaggen.

Een aanroep zoals deze:

pictureBox1.Load(@<a href="https://chart.googleapis.com/chart?chst=d_bubble_icon_text_small&chld=ski|bb|Wheeee!|FFFFFF|000000">https://chart.googleapis.com/chart?chst=d_bubble_icon_text_small&chld=ski|bb|Wheeee!|FFFFFF|000000</a>);

is dus een gruwelvoor een interaction desginer 🙂

Helaas staat deze service als ‘deprecated’ te boek en het is onduidelijk wanneer de service opgeheven wordt of dat de API veranderd wordt. Op http://googledevelopers.blogspot.nl/2012/04/changes-to-deprecation-policies-and-api.html wordt over april 2014 en maximaal 2015 gesproken. Wellicht is http://code.google.com/p/zxing/ dan een alternatief. Wil je met de hand een QR code aanmaken, kijk dan eens op http://zxing.appspot.com/generator

Een WPF StoryBoard starten vanuit het MVVM Viewmodel

 

In need of an English translation? Please drop me a note.

Sinds enige tijd werk ik aan een project waarbij de UI volledige in WPF4 is geschreven. Hierbij heb ik mezelf het doel gesteld om de architectuur volledig op MVVM te baseren.

Dit betekent concreet dat de schermen (de Views) geen code-behind hebben maar via een ViewModel interactie hebben met het Model. Alle schermwijzigingen worden met bindings en commands afgehandeld.

Zelf MVVM implementeren kan vast wel maar er zijn ook veel frameworks: grote, kleine, goede en foute… Uiteindelijk ben ik bij MVVMLight uitgekomen.

Ontwikkelen in WPF blijft door het gebruik van MVVM een feest, ondanks de steile leercurve maar dankzij de strikte scheiding tussen de te tonen data (ViewModel) en de representatie (XAML).

En ik ben ook begonnen met het gebruik van StoryBoards. Dit zijn notaties om de vorm verschijning en plaats van Xaml objecten aan te passen op een tijdslijn. Zo is het mogelijk om animaties in de UI te verwerken die wel degelijk van functioneel nut kunnen zijn.

StoryBoards worden bij voorkeur aan gebeurtenissen gehangen. Als voorbeeld toon ik hier hoe een plaatje langzaam zichtbaar wordt bij het starten van de applicatie door de Opacity in vijf seconden van 0 naar 1 te laten lopen.

Hieronder is de XAML beschreven en de code in het viewmodel. Dit zijn Snippets die zo te combineren zijn met een MvvmLight WPF4 template project.

<Grid x:Name="LayoutRoot"
      Width="284">
  <TextBox FontSize="36"
           FontWeight="Bold"
           Foreground="Purple"
           Text="{Binding WelcomeTitle}"
           VerticalAlignment="Center"
           HorizontalAlignment="Center"
           TextWrapping="Wrap"
           Margin="12,12,42,100" />
  <Image Height="51"
         Name="image"
         Source="Assets\troll-face.png"
         Opacity="0.5"
         Stretch="Uniform"
         HorizontalAlignment="Left"
         Margin="178,182,0,0"
         VerticalAlignment="Top"
         Width="61">
    <Image.Triggers>
      <EventTrigger RoutedEvent="Image.Loaded">
        <BeginStoryboard Name="MyBeginStoryboard">
          <Storyboard>
            <DoubleAnimation Storyboard.TargetProperty="Opacity"
                             From="0"
                             To="1"
                             Duration="0:0:5" />
          </Storyboard>
        </BeginStoryboard>
      </EventTrigger>
    </Image.Triggers>
  </Image>
</Grid>

Er staat een Textbox op de pagina voor de invoer van een string en een plaatje. Dit plaatje bevat een StoryBoard dit wordt afgevuurd als de pagina wordt geladen voor vertoning.

De Textbox is gebonden aan de WelcomeTitle op het ViewModel.

public class MainViewModel : ViewModelBase
{
  public MainViewModel()
  {
    WelcomeTitle = "Hello";
  }

  public const string WelcomeTitlePropertyName = "WelcomeTitle";
  private string _welcomeTitle = string.Empty;
  public string WelcomeTitle
  {
    get
    {
      return _welcomeTitle;
    }
    set
    {
      if (_welcomeTitle == value)
      {
        return;
      }

      _welcomeTitle = value;

      RaisePropertyChanged(WelcomeTitlePropertyName);
    }
  }
}

De uiteindelijke functionaliteit is eenvoudig. Indien de Textbox wordt verlaten zal de Getter van WelcomeTitle uitgevoerd worden.

Het scherm zier er zo uit:

Mijn wens is dat het Troll-plaatje pas getoond wordt als de textbox wordt verlaten en de WelcomeText korter dan drie karakters is.

Maar door de MVVM ‘belemmering’ (ik kan geen (visuele) XAML onderdelen direct vanuit code aanraken en aanspreken) wordt het lastig om StoryBoards aan te spreken. Een Command werkt ook niet want die vuurt juist in de richting van het viewmodel af (bv. indien de gebruiker een knop indruk of via de MVVMLight EventToCommand).

Ik moet iets anders gebruiken en het antwoord is: DataTriggers.

Het is mogelijk om de XAML naar wijzigingen op het ViewModel te laten luisteren en hierop te laten reageren.

Wat heb ik nodig?

  1. Een bindable (boolean) property op het ViewModel. Hiervoor voeg ik de “ShowTroll” property toe aan het ViewModel.
  2. Op het Viewmodel moet de nieuwe property van waarde kunnen veranderen. Dit gebeurt in de Setter van de WelcomeTitle. Als een waarde met een lengte kleiner dan drie karakters voorbij komt, dan wordt de ShowTroll op True gezet.
  3. Een Button in de Xaml. Deze doet op zich niets maar kan wel de Focus krijgen. Als deze aangeraakt wordt, zal de TextBox de focus verliezen en wordt de Setter van WelcomeTitle uitgevoerd. Een dummy dus.
  4. Een DataTrigger op de Image, gekoppeld aan de ShowTroll boolean
  5. Twee StoryBoards. Als de ShowTroll op true wordt gezet, zal de ene afgespeeld worden en anders de andere.

Dit betekent dus dat het viewmodel met een ShowTroll property wordt  uitgebreid en dat deze verandert in de Setter van de WelcomeTitle property:

public class MainViewModel : ViewModelBase
{
  public MainViewModel()
  {
    WelcomeTitle = "Hello";
  }

  public const string WelcomeTitlePropertyName = "WelcomeTitle";
  private string _welcomeTitle = string.Empty;
  public string WelcomeTitle
  {
    get
    {
      return _welcomeTitle;
    }
    set
    {
      if (_welcomeTitle == value)
      {
        return;
      }

      _welcomeTitle = value;
      ShowTroll = (_welcomeTitle.Length < 3); // Force data change
      RaisePropertyChanged(WelcomeTitlePropertyName);
    }
  }

  public const string ShowTrollPropertyName = "ShowTroll";
  private bool _ShowTroll = false;
  public bool ShowTroll
  {
    get
    {
      return _ShowTroll;
    }
    set
    {
      if (_ShowTroll == value)
      {
        return;
      }

      _ShowTroll = value;
      RaisePropertyChanged(ShowTrollPropertyName);
    }
  }
}

En er wordt dus in de Xaml een Button toegevoegd en de Image wordt iets aangepast. Zie dat de Opacity standaard nul (volledige doorzichtig) is. En er zijn twee StoryBoards om de Opacity binnen twee seconden op één of op nul te brengen.

De DataTrigger is aan de ShowTroll property gekoppeld en reageert zowel op True als op False.

<Grid x:Name="LayoutRoot"
      Width="284">
  <TextBox FontSize="36"
           FontWeight="Bold"
           Foreground="Purple"
           Text="{Binding WelcomeTitle}"
           VerticalAlignment="Center"
           HorizontalAlignment="Center"
           TextWrapping="Wrap"
           Margin="12,12,42,100" />
  <Button Content="Button"
          Height="23"
          HorizontalAlignment="Left"
          Margin="31,226,0,0"
          Name="button1"
          VerticalAlignment="Top"
          Width="75" />
  <Image Height="51"
         Name="image"
         Source="Assets\troll-face.png"
         Opacity="0"
         Stretch="Uniform"
         HorizontalAlignment="Left"
         Margin="178,182,0,0"
         VerticalAlignment="Top"
         Width="61">
    <Image.Resources>
      <Storyboard x:Key="TrollBeginStoryboard">
        <DoubleAnimation Storyboard.TargetProperty="Opacity"
                         From="0"
                         To="1"
                         Duration="0:0:2" />
      </Storyboard>
      <Storyboard x:Key="TrollEndStoryboard">
        <DoubleAnimation Storyboard.TargetProperty="Opacity"
                         From="1"
                         To="0"
                         Duration="0:0:2" />
      </Storyboard>
    </Image.Resources>
    <Image.Style>
      <Style>
        <Style.Triggers>
          <DataTrigger Binding="{Binding ShowTroll}"
                       Value="true">
            <DataTrigger.EnterActions>
              <BeginStoryboard>
                <Storyboard>
                  <StaticResource ResourceKey="TrollBeginStoryboard" />
                </Storyboard>
              </BeginStoryboard>
            </DataTrigger.EnterActions>
            <DataTrigger.ExitActions>
              <BeginStoryboard>
                <Storyboard>
                  <StaticResource ResourceKey="TrollEndStoryboard" />
                </Storyboard>
              </BeginStoryboard>
            </DataTrigger.ExitActions>
          </DataTrigger>
        </Style.Triggers>
      </Style>
    </Image.Style>
  </Image>
</Grid>

Hiervoor gebruiken we zowel de EnterActions als de ExitActions.

Dit geeft dus als effect dat als er een langere tekst is ingevoerd, de ‘troll’ niet zichtbaar is.

Maar als de gebruiker een tekst korter dan drie karakters invult, dan wordt binnen twee seconden de Troll zichtbaar.

En indien de tekst weer langer wordt gemaakt, dan is de Troll weer verstopt.

Ik wil in dit voorbeeld aangeven dat het relatief eenvoudig is om complexe UI veranderingen door te voeren door slecht een property op een ViewModel te manipuleren. Hiermee wordt het opeens mogelijk om binnen StoryBoards meerdere objecten te wijzigen. Dit is oogsnoep voor de gebruiker en zo wordt het een visueel feestje voor zowel de ontwikkelaar (of moet ik zeggen: Interactive Designer) en de gebruiker.

Eenvoudig PDF printen in C#

In need of an English translation? Please drop me a note!

Printen in het .Net framework is op zich niet zo lastig. En met de komst van WPF en de bijbehorende XpsDocumentWriter kan bv. handig gebruik gemaakt worden van de FlowDocument klasse en de PrintQueue klasse met bijbehorende CreateXpsDocumentWriter methode. Hiermee kun je zelf je templates opmaken, mergen en printen.

Maar specifiek een aangeboden PDF printen is een stuk lastiger. Met de hand lijkt dit eenvoudig, je start gewoon Adobe Reader of iets dergelijks.

Maar een PDF vanuit code uitprinten is niet eenvoudig. De opmaak binnen PDF’s wordt niet direct door de meeste printers herkend. Op het internet zwerven veel oplossingen rond allemaal met hun eigen voor- en nadelen. Adobe Reader is bv. gratis maar geeft een ‘nag’ screen en er zijn commerciële oplossingen maar die zijn niet bepaald goedkoop.

Voor mijn huidige project heeft het team gekeken naar de mogelijkheid om GhostScript te gebruiken. Dit is een bibliotheek om PDF naar ‘niet-postscript’ om te zetten. We zijn met name geïnteresseerd in PCL, dit kunnen de meeste (HP) laserprinters wel aan. Op GhostScript zit een GNU licentie met beperkt commercieel gebruik.

En wat blijkt, in slechts enkele stappen komt het printen van PDF ook voor .Net ontwikkelaars binnen bereik!

Stap 1: Download GhostScript en installeer deze lokaal. De 32 bits versie is een prettige keuze, vooral in combinatie met de andere benodigdheden. Deze werkt ook met een 64 bits Windows7. Refereer naar de gsdll32.dll in je C# project.

We zijn dus geïnteresseerd in die gsdll32.dll en deze is geschreven in C . Gelukkig heeft Matthew Ephraim al de moeite genomen om deze in C# te verpakken. Deze bibliotheek heet heel toepasselijk GhostScriptSharp. De broncode kan je ophalen bv. op GitHub.

Deze wrapper rond de 32 bits GhostScript dll is heel aardig. Er is via de methode GenerateOutput() de mogelijkheid beschikbaar om een PDF om te zetten naar PCL. Als onderdeel van de instellingen moet wel een ‘Device’ meegegeven worden. Hier heb ik een simpele aanpassing moeten maken op GhostScriptSharp. De GhostscriptDevices enum krijgt nu de extra ljet4 voor PCL support want die ontbrak. Waarom deze in de huidige versie niet aanwezig is, is mij onbekend.

Stap 2: download nu de GhostScriptsharp code, integreer deze in je eigen code en breid de enum even uit met de keuze ‘ljet4’. Zie dat die broncode standaard naar de 32 bits versie van GhostScript refereert.

Als laatste moet nu de, door GhostScript uit de PDF, gegenereerde PCL naar de printer gestuurd worden. Jouw printer dient dus wel PCL te ondersteunen :-).

Hiervoor gebruiken we een voorbeeld op de MSDN van Microsoft zelf. Dit voorbeeld gebruikt de Win32 Spooler Application Programmer Interfaces (APIs) en dit werkt ook prima samen met Windows7. De in het voorbeeld genoemde RawPrinterHelper klasse is prima. Er zitten wel enkele geheugenlekjes in (geen usings op de FileStream en de BinaryReader) dus een kleine aanpassing is gewenst.

Stap 3: Integreer de voorbeeldcode van Microsoft in je project en repareer even de RawPrinterHelper.SendFileToPrinter() methode.

Nu wordt het mogelijk om alles bij elkaar te brengen in één aanroep:

string pdfFileName = "test.pdf";
string tempFileName =
    Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
GhostscriptSettings gss = new GhostscriptSettings
{
  Size = new GhostscriptPageSize() { Native = GhostscriptPageSizes.a4 },
  Device = GhostscriptDevices.ljet4,
  Resolution = new Size(600, 600)
};

GhostscriptSharp.GhostscriptWrapper.GenerateOutput
    (pdfFileName, tempFileName, gss);
RawPrinterHelper.SendFileToPrinter(printerName, tempFileName);
File.Delete(tempFileName);

Eerst stellen we een naam samen voor een tijdelijk bestand. Vervolgens laten we via GhostScript vanuit een aangeboden PDF dit tijdelijk bestand vullen met PCL code (op A4 formaat met een resolutie van 600 dpi). En vervolgens laten we dit PCL bestand ruw naar de printer sturen. En achteraf verwijderen we natuurlijk nog even het tijdelijk bestand.

Dit moet voldoende zijn. Natuurlijk moet deze oplossing uitvoerig getest worden doordat het een heleboel zaken integreert… Maar in onze testopstelling functioneert het heel aardig. Persoonlijk had ik liever niet met een tijdelijk bestand op schijf gewerkt, maar met bijvoorbeeld een memorystream.