Category Archives: Scripting

Powershell srcset image generator

If you have a website and SEO matters for you, then you probably had to optimize images. To this aim, you may want to have responsive images. As explained here,

a responsive image is an image which is displayed in its best form on a web page, depending on the device your website is being viewed from.

One of the modern way to serve quickly responsive images is to benefit from the srcset html attribute. Shortly, depending on parameters and your viewport (i.e. browser window) the srcset attribute will tell the browser to download the best appropriate image for the current display.

For example, if you put the following HTML element

<img src="images/fcnantes-champions-95.jpg"
srcset="images/fcnantes-champions-95.jpg 200w, images/fcnantes-champions-95-400.jpg 400w,
images/fcnantes-champions-95-600.jpg 600w,
images/fcnantes-champions-95-800.jpg 800w">

Your server logic can serve up to four different images representing the same pictures.

You may guess that creating all this different resized pictures can be painful manually. In this blog post we propose the following Powershell script to help you for the automation of this task.

Param ( [Parameter(Mandatory=$True)] [ValidateNotNull()] $imageSource, [Parameter(Mandatory=$true)][ValidateNotNull()] $quality )

if (!(Test-Path $imageSource)){throw( "Cannot find the source image")}
if ($quality -lt 0 -or $quality -gt 100){throw( "quality must be between 0 and 100.")}

[void][System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
$resolvedPath = Join-Path $PWD -ChildPath $imageSource
$bmp = [System.Drawing.Image]::FromFile($resolvedPath)

#hardcoded canvas size...
$canvasWidths = @(200, 400, 600, 800)

foreach($canvasWidth in $canvasWidths){
    #Encoder parameter for image quality
    $myEncoder = [System.Drawing.Imaging.Encoder]::Quality
    $encoderParams = New-Object System.Drawing.Imaging.EncoderParameters(1)
    $encoderParams.Param[0] = New-Object System.Drawing.Imaging.EncoderParameter($myEncoder, $quality)
    # get codec
    $myImageCodecInfo = [System.Drawing.Imaging.ImageCodecInfo]::GetImageEncoders()|where {$_.MimeType -eq 'image/jpeg'}

    #compute the final ratio to use
    $ratioX = $canvasWidth / $bmp.Width;
    $ratioY = $canvasWidth / $bmp.Height;
    $ratio = $ratioY
    if($ratioX -le $ratioY){
        $ratio = $ratioX
    }

    #create resized bitmap
    $newWidth = [int] ($bmp.Width*$ratio)
    $newHeight = [int] ($bmp.Height*$ratio)
    $bmpResized = New-Object System.Drawing.Bitmap($newWidth, $newHeight)
    $graph = [System.Drawing.Graphics]::FromImage($bmpResized)

    $graph.Clear([System.Drawing.Color]::White)
    $graph.DrawImage($bmp,0,0 , $newWidth, $newHeight)

    $targetFileName = [System.IO.Path]::GetFileNameWithoutExtension($imageSource) + "-" + $canvasWidth + ".jpg"
    $dir = [System.IO.Path]::GetDirectoryName($resolvedPath)
    $targetFilePath = Join-Path $dir -ChildPath $targetFileName
    Write-Host "Saving file" $targetFilePath
    #save to file
    $bmpResized.Save($targetFilePath,$myImageCodecInfo, $($encoderParams))
    $graph.Dispose()
    $bmpResized.Dispose()
}
$bmp.Dispose()

Now you can simply invoke the script like this: .\SrcsetBuilder.ps1 "..\images\MyImage.jpg" 85. Then all generated images: MyImage-200.jpg, MyImage-400.jpg, MyImage-600.jpg, MyImage-800.jpg are located next to MyImage.jpg.
You can modify the generated images widths by changing the values in the array $canvasWidths (line 11).

Programming well structured Javascript stored procedures for DocumentDB with Typescript and SystemJs

EDIT: code sample on github https://github.com/bpatra/StoredProcedureGeneration

If you are using DocumentDB you may had to write your own stored procedure. A stored procedure is a function written in Javascript that runs on the DocumentDB cloud infrastructure. It may reduce performance problem or make you execute some queries that are not supported yet through the REST API such as aggregate function.

A stored procedure should be registered as a single function of the form:

function myStoredProcedure(arg1, arg2){ /* you can place all the arguments you want here*/
    //The body of the function here

    //you set the response like this
    var context = getContext();
    context.setBody(myResult);
}

You can create function inside the myStoredProcedure function body. However, you cannot create other functions in the file otherwise DocumentDB will complain. This is quite annoying because you probably want to create independent and reusable pieces of code for testability or simply for the sake of readability. The problem comes from the fact that you cannot really use out-of-the box third party module management libraries such as requireJS, commonJS or SystemJS. This sounds no good. Is that means we are forced to inline all our code in a big not modular and un-testable Javascript file!?!?

The answer is no, in this blog post I will show you the solution we implemented at Keluro to overcome this problem. This solution is based on SystemJs and SystemJs-Builder to create a standalone function where all modules/class dependencies are embedded in the stored procedure single function which acts as our entry point. The code snippets presented in the following are extracted from the following git repository.

In this article, we will use Visual Studio as an IDE but it is not mandatory. Actually, it is only to simplify the options settings for compiling Typescript files, you can invoke the compiler manually exactly with the same set of options.

In the following, we will take an example where the stored procedure computes the sum of input arguments. Therefore, we create a Typescript class for the core of our stored procedure called Utilitary that contains a method called sumValues.

A typescript class used in DocumentDB stored procedure

A typescript class used in DocumentDB stored procedure

Then we create the entry point of the stored procedure in a Typescript file that uses the DocumentDB current context. We benefit from the typings from documentdb-server.d.ts that defines the IContext interface.

MyStoredProcedure typescript file executed by DocumentDB

MyStoredProcedure typescript file executed by DocumentDB

We compile the Typescript files has SystemJs modules and we redirect all generated Typescript in the directory out-js. As I told you, no need of VisualStudio to do this, you can achieve the same result by invoking the Typescript compiler with similar options.

ompiling options set in Visual Studio

ompiling options set in Visual Studio

If you look at the generated Typescript you will get something that looks like

System.register(["Utilitary"], function(exports_1, context_1) {
    "use strict";
    var __moduleName = context_1 && context_1.id;
    
     /* ETC */
});
//# sourceMappingURL=myStoredProcedure.js.map

If you try to run such a Javascript source code directly with DocumentDB you will get an error. These modules are meant to run with System.js and in the case of a stored procedure you cannot reference any third party library such as System.js. This is where SystemJs-Builder will come into play. SystemJs-builder will package everything so that your modules are independent of System.js and they can be used as a standalone file.

To invoke SystemJs-Builder you need to use Node.js. In the sample git repository, you will have to hit ‘npm install’ to restore the SystemJs-Builder Node package. When the Typescript files are compiled invoke the node script “documentdb_storedprocedure_builder.js” at the root of the repository. This script basically executes two tasks. First, it generates a standalone Javascript file with SystemJs-Builder. Secondly, because DocumentDB explicitly needs a file with one function and not an executable Javascript script, we wrap this code inside a function that will act as our entry point for the stored procedure.

We also retrieve the arguments passed to the storedprocedure procedure function in a variable called storedProcedureArgs that is kept in the global namespace. The resulting file is generated and put in the directory generated-procedure. Finally, this file contains what we needed: a standalone and executable by DocumentDB Javascript function. With this approach all Typescript classes can be reused for other stored procedures , for unit tests or anywhere in your Typescript code base.

There are probably thousands of alternatives to create testable and decoupled stored procedures. We liked this approach because it reuses the same tools that we were already using for our single page applications: Typescript and SystemJs. To conclude let me thank Olivier Guimbal who showed us some months ago how Typescript, SystemJs and SystemJs-Builder worked well together.

Resize image and preserve ratio with Powershell

My recently created company website Keluro has two blogs: one in french and one in english. The main blog pages are a preview list of the existing posts. I gave the possibility to the writer to put a thumbnail image in the preview. It’s a simply <img /> tag where a css class is responsible for the resizing and to display the image in a 194px X 194px box while keeping the original aspect ratio. Most of the time this preview is a reduction of an image that is displayed in the blog post. Everything was fine until I found out that the these blog pages did not received a good mark while inspecting them with PageSpeedInsights . It basically says that the thumbnails were not optimized enough… For SEO reasons I want these blog pages to load quickly so I needed to resize these images once for all even if it has to duplicate the image.

Resizing and keeping aspect ratio

Resizing two pictures with landscape and portrait aspect ratio to make them fill a given canvas.

I think that most of us already had to do such kind of image resizing task. You can use many available software to do that: Paint, Office Picture Manager, Gimp, Inkscape etc. However, when it comes to manipulate many pictures, it could be really useful to use a script. Let me share with you this Powershell script that you can use to resize your .jpg pictures. Note that there is also a quality parameter (from 1 to 100) that you can use if you need to compress more the image.

Param ( [Parameter(Mandatory=$True)] [ValidateNotNull()] $imageSource,
[Parameter(Mandatory=$True)] [ValidateNotNull()] $imageTarget,
[Parameter(Mandatory=$true)][ValidateNotNull()] $quality )

if (!(Test-Path $imageSource)){throw( "Cannot find the source image")}
if(!([System.IO.Path]::IsPathRooted($imageSource))){throw("please enter a full path for your source path")}
if(!([System.IO.Path]::IsPathRooted($imageTarget))){throw("please enter a full path for your target path";)}
if ($quality -lt 0 -or $quality -gt 100){throw( "quality must be between 0 and 100.")}

[void][System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
$bmp = [System.Drawing.Image]::FromFile($imageSource)

#hardcoded canvas size...
$canvasWidth = 194.0
$canvasHeight = 194.0

#Encoder parameter for image quality
$myEncoder = [System.Drawing.Imaging.Encoder]::Quality
$encoderParams = New-Object System.Drawing.Imaging.EncoderParameters(1)
$encoderParams.Param[0] = New-Object System.Drawing.Imaging.EncoderParameter($myEncoder, $quality)
# get codec
$myImageCodecInfo = [System.Drawing.Imaging.ImageCodecInfo]::GetImageEncoders()|where {$_.MimeType -eq 'image/jpeg'}

#compute the final ratio to use
$ratioX = $canvasWidth / $bmp.Width;
$ratioY = $canvasHeight / $bmp.Height;
$ratio = $ratioY
if($ratioX -le $ratioY){
  $ratio = $ratioX
}

#create resized bitmap
$newWidth = [int] ($bmp.Width*$ratio)
$newHeight = [int] ($bmp.Height*$ratio)
$bmpResized = New-Object System.Drawing.Bitmap($newWidth, $newHeight)
$graph = [System.Drawing.Graphics]::FromImage($bmpResized)

$graph.Clear([System.Drawing.Color]::White)
$graph.DrawImage($bmp,0,0 , $newWidth, $newHeight)

#save to file
$bmpResized.Save($imageTarget,$myImageCodecInfo, $($encoderParams))
$graph.Dispose()
$bmpResized.Dispose()
$bmp.Dispose()

Now suppose that you have saved and named the script above “MakePreviewImages.ps1”. You may use it in a loop statement such as the following one where we assume that MakePreviewImages.ps1 is located under the current directory and the images are in a subfolder called “images”.

Get-ChildItem .images -Recurse -Include *.jpg | Foreach-Object{
   $newName = $_.FullName.Substring(0, $_.FullName.Length - 4) + "_resized.jpg"
     ./MakePreviewImages.ps1 $_.FullName $newName 75
   }

Executing PSake build script with Teamcity

For my build tasks I have been using MSBuild for a while. I found out that it is fine to use it for standard build tasks such as invoking msbuild.exe itself. However, when it comes to really custom actions it is really painful. I did not want to struggle any longer with xml config files and would like to stay as close as possible to a simple procedural programming language. Most of all I was fed up by the quoting issues when invoking external executables. When writing such actions I wanted to stick to a shell scripting language that I already know. Still, basic scripting can be a little bit improved when it comes to build process. To be precise, the notion of task (or target) is extremely handy because you can split a build step in sub tasks that you may combine differently depending on the build config. While it looks like overkill for a small project it will ease your life in large projects where packaging can be complex.

The tool that I will present in this post is called PSake (pronounce saké like the asian alcohol) and is described by the Wikipedia as

a domain-specific language and build automation tool written in PowerShell to create builds using a dependency pattern similar to Rake or MSBuild.

This was all I needed: a build tool in Powershell.

Even if I will not cover this in the present post, one of the main benefit of using Powershell for build scripts is the possibility to use directly Powershell extensions such as Azure or Sharepoint Cmdlets. Even if you do not need it right now, they may become extremely useful in the future of your Windows based software project.

In this post I will describe how to use PSake for a very simple build task: patching the AssemblyInfo.cs file for a visual studio .NET solution. I will also show you the organization of the targets that I have chosen.

Let us recall that the version of the .NET assembly produced by the compilation of your C# project uses the AssemblyInfo.cs file that you can find under the /Properties folder. The lines that are automatically generated in the AssemblyInfo.cs file regarding the assembly version are

[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

Consequently, the task has to patch the AssemblyVersion so that it contains major.minor while the AssemblyFileVersion will be major.minor.build. Once the task will be finished all AssemblyInfo.cs in the code source repository will be patched similarly, for example with [assembly: AssemblyVersion("6.3")] and [assembly: AssemblyFileVersion("6.3.567")]. If you are not familiar with product versioning you may read the wikipedia page. Here we chose a major.minor.build sequence where the major and minor numbers are fully handled by the owner of the project. However, the .build number is provided by the continuous integration system which will be Teamcity in our case. Similarly to food industry where, given the number of a ready-made meal you are supposed to be able to track back where the beasts came from, in software, you should be able from the product version to track back the source of your product and its external dependencies. This is why both source code and build history are precious and why the Teamcity database should also be backed up.

The task presented here may not the best advocate for PSake over MSBuild XML configs because using the <FileUpdate> command performs the same kind of patch easily. In addition the MSbuildExtensionPack has a built in AssemblyInfo task for this purpose. But, if you are a .NET developer I am pretty sure you will be at ease, then think as an illustration for PSake.

Here is the source code for the task.

The outer braces: task PathAssemblyInfo defines the scope of the target. The command does not depend from where the script is run because we use the $PSScriptRoot variable (available since Powershell 3.0). It basically looks for all AssemblyInfo files in the solution directory and patch them with the appropriate version numbers. The detailed implementation of the functions GetAssemblyVersion, GetAssemblyFileVersion and PatchFile can be found here.

Now let us look on how to combine and invoke the PSake targets from Teamcity. I have a /build directory at the root of the repository which looks like

The organisation of build target with PSake

The organisation of build target with PSake

The PSake project is located under the /build folder. In the /targets directory we put all targets where one target equals one file with the same name. The bootstrapTargets.ps1 loads all build targets that are put in the subdirectory with the same name. In bootstrapTargets.ps1 I also put the high level targets, the one that will be called by the Continous Integration. Here, I have defined a high level target Example that executes first our PatchAssemblyInfo then another target that I have called RenameMSI (only for the example). You can also put in bootstrapTargets.ps1 some functions that will be reused by the different targets.

Now see how to invoke the PSake Example task within Teamcity. Create a Powershell using at least the 3.0 version.

Invoke the Example PSake task within TeamCity

Invoke the Example PSake task within TeamCity

The script in the Teamcity editor (and only this one) assumes the current directory is the repository root. The first line imports the module while second one invoke the Example task using PSake. The third line below is important so that exceptions thrown in the script appear as build failures.
if ($psake.build_success -eq $false) { exit 1 } else { exit 0 }

To conclude, I would say that PSake is good alternative to those who know Powershell and want to use less XML for their builds.

No hdmi sound without OS reboot? Restart the drivers…

Edit: end july 2015 the problem is now fixed for me with windows 10.

This post blog follows a problem that I encountered when I upgraded my laptop to windows 8.1. Precisely, the hdmi sound stops working immediately when I connect the hdmi cable to my television. The hardware works fine because if the OS is reboot with hdmi cable plugged, then the TV as a sound playback device is available. This is terribly annoying, you do not want to reboot each time you want to use your TV as a display device. While searching the internet for a solution, I discovered that I am not the only one with this problem. Therefore, I will try to expose my solution with many details in order to make it reusable by others who would stumble on this post with the same problem.

Assuming that you are in the same, or a close, situation: the hdmi sound works well when Windows is reboot with the cable plugged in. Consequently, when everything is working, if you right click on the sound icon in the tray bar and select “playback devices” you should be able to see the TV in the device playbacks .

The list of available playback devices.

The list of available playback devices.

Before going any further the first thing to do is to update the drivers. This is quite simple, right click on the windows menu at the bottom left of your desktop screen and select the device manager. My advice is to update all drivers for the two entries in the tree view “display adapters” and “sound, video and game controllers”.

The device manager

The device manager

Once all drivers have been updated, check that the problem still occurs (restart the OS once at least) and if it does you may be interested in the following.

Upgrading driver software...

Upgrading driver software

So even after updating the drivers, you still need the reboot to get the sound. Actually, the drivers managing the hdmi need to be restarted and that is what we are going to do manually, without restarting the OS. To perform such action, we are going to need devcon.exe which is a tiny program distributed freely by Microsoft with the Windows Driver Kit. Download it here (you do not need Visual studio).

After the (silent) installation of WDK you may find devcon.exe in the the path “C:\Program Files (x86)\Windows Kits\8.1\Tools\x64”. You will notice that you have two directories in Tools the “/x64” and the “/x86” (i.e 32 bits), use the one corresponding to your system (to know more on 32 bits vs 64 bits check this).

WARNING: devcon.exe error messages are extremely misleading (read completely wrong…). Indeed, if you are using the x86 version instead of the x64 version or if you are trying to restart the drivers (see below) without administrators right you will still have the same error.: “No matching devices found”. Consequently, do not try to interpret the error raised by devcon.exe.

listmedia

“devcon.exe listclass media” executed in powershell using conemu terminal

Now, we are going to restart the two drivers using devcon.exe. First, let us see all drivers dedicated to sound, then type in your command prompt (or better with powershell) run as administrator: <pathToDevCon>/devcon.exe listclass media

The response here is a list of two items, we are going to retain the first one, “Intel (R) display”, which was the audio adapter used for the hdmi (see the first screen shot of this post). The driver Id: HDAUDIOFUNC_01&VEN_8086&DEV_2807&SUBSYS_80860101&REV_10004&36161A1D&0&0001 is going to be needed. If you are using powershell you may use the Out-File command to write it down in a text file…

You can try to restart it directly by typing (in command line run as administrator): <pathToDevCon>/devcon.exe restart “@<DRIVER_ID>”.
Note that the @ symbol is inside the quotes which may surprise you if you are a .NET developer…

Unfortunately, it does not seem to be sufficient and the system also needs to reboot the display adapter driver after that. So we are going to do the same action but for display adapter driver: we type in an admin command line:
<pathToDevCon>/devcon.exe listclass display

devcon.exe listclass display

devcon.exe listclass display

Then now if you restart the driver listed here as “Intel(R) HD Graphics Family” then the HDMI sound device playback should be available if the cable is connected. To do so execute:

<pathToDevCon>/devcon.exe restart “@PCIVEN_8086&DEV_0A16&SUBSYS_130D1043&REV_093&11583659&0&10”

The Id above is mine, obviously you should use yours.

Fine but this is not over yet. Indeed, you do not want to do all this each time you are connecting your hdmi cable with your TV. What we are going to do right now, is to add a powershell script that will automated this process so that you will just have to click on one icon when you will want your TV sound. If you have never run powershell script on your machine, then the execution of ps1 file (powershell script) will not be allowed. Read this to enable powershell script execution (basically you will just have to type in a powershell console, run as admin, Set-ExecutionPolicy Unrestricted).

Here is the script that you can use. I have added two instructions to enable the drivers, it seems to be sometimes useful when you plug/unplug the hdmi cable several times. All you have to do to make it work is to change the path to devcon.exe and the id. You can save it to the place of your choice such as the Desktop with a .ps1 extension (e.g. restart_drivers.ps1)

Remind that to be effective this .ps1 file should be executed with administrator rights. Remind also, that devcon.exe will only tell you that the drivers cannot be found if you are not with admin rights. So I am suggesting to make the script more easily run in admin mode, you can put a powershell.exe shortcut next to the .ps1 script file. By right clicking on the shortcut file go to Properties and fill the target property as follows. Target:”powershell.exe restart_drivers.ps1″. Then, in Advanced… select Run as administator.

A shortcut to run restart_drivers.ps1 directly with admin right

A shortcut to run restart_drivers.ps1 directly with admin right

That is all, no when you will connect your hdmi cable you will only have to click on the shortcut and enjoy the sound from your TV.