At a client we have a PDF template that needs to be used for registering users. When this is updated, the template is overriden. But it would be nice to be able to easily see what changed between the two.
Well, this is possible :)
You can use Imagemagick and Ghostscript to do this.
You should be able to just do the below:
magick compare old.pdf new.pdf diff.pdf
But that didn't seem to work well. What seems to work better is to rather convert the PDF to an image first, and then compare each page.
magick convert -density 300 -quality 100 old.pdf old.png
magick convert -density 300 -quality 100 new.pdf new.png
magick compare old-0.png new-0.png diff-0.png
Depending on the options you can get better or worse results. Changing the colorspace to CMYK for example could yield better results, or maybe using options to blur/sharpen/despeckle the image too. Try play around with the options to see better results.
The best results I had was actually via using Adobe Acrobat to first export the PDF to images, and then run the compare. I still need to figure out why, because unfortunately I only have the license at work, so this won't always be an option. I'll hopefully update this post in future to show my favourite variation :)
Monday, March 20, 2017
diff PDF files
Tuesday, February 21, 2017
Modern Database Development Practices
Back in November 2012 I presented on this topic at Entelect's Dev Days.
I've also done a blog post previously on setting up Flyway.
I keep referring back to the same links and concepts and this post is here just for that, as a pointer to good resources and brief points about this topic.
I may revisit it and put down my own consolidated content, but for now this will do.
I've also done a blog post previously on setting up Flyway.
I keep referring back to the same links and concepts and this post is here just for that, as a pointer to good resources and brief points about this topic.
I may revisit it and put down my own consolidated content, but for now this will do.
- Reading
- Evolutionary Database Design
Martin Fowler, 2003 - Agile Database Techniques: Effective Strategies for the Agile Software Developer
Scott Ambler, 2003 - Refactoring Databases: Evolutionary Database Design
Scott Amber and Pramod Sadalage, 2006 - Catalog of Database Refactorings
Scott Ambler - Three Rules for Database Work
K. Scott Allen, 2008 - The Baseline
K. Scott Allen, 2008 - Change Scripts
K. Scott Allen, 2008 - Versioning Databases - Views, Stored Procedures, and the Like
K. Scott Allen, 2008 - Versioning Databases - Branching and Merging
K. Scott Allen, 2008 - Scott Ambler's Articles
Scott Ambler - Stairway to Database Source Control
SQL Server Central - Martin Fowler's Practices
- DBAs collaborate closely with developers
- Everybody gets their own database instance
- Developers frequently integrate into a shared master
- A database consists of schema and test data
- All changes are database refactorings
- Automate the refactorings
- Automatically Update all Database Developers
- Clearly separate all database access code
- K. Scott Allen's 3 Rules
- Never use a shared database for development work
- Always have an authoritative source for your schema
- Always version your database
- Tools
Labels:
agile,
continuous deployment,
continuous integration,
databases,
redgate,
refactoring,
ssdt
Wednesday, February 15, 2017
C# - Testing that different cultures won't affect formatting
Ever worked on a system where you write code and test it and it all works perfect, but then maybe a unit test starts failing on a build server, or maybe a report looks wrong to the consumers of the report, all because it formatted a number to "12345,67" instead of "12345.67"?
This tip will help you.
First, lets assume we have this code:
And a nice little unit test for it:
This works perfectly fine. Lets even imagine that all our machines all have the same setup, and all are set to use the same regional settings. Great, nothing should ever break.
Until maybe Microsoft releases a patch to Windows that changes our regional settings to be "correct" - in fact, South Africa should be using a comma as a separator... even though none of us use this standard :D
So then it breaks our code, and our business rules that disagree with it.
Well, the good news is we can change the regional settings of the running thread, by changing its CultureInfo details. Here is a little utility class to do so:
We can now update our test to be a bit more specific:
Now we have a test that will fail consistently! Time to fix the code. One way of doing this is realizing that there is an overload of Decimal.ToString that takes in a CultureInfo object. We actually can use the InvariantCulture as below:
The test passes and we now know for sure that regional settings won't affect our code.
This tip will help you.
First, lets assume we have this code:
public class ReportFormatter
{
public string Format(decimal value)
{
return value.ToString();
}
}
And a nice little unit test for it:
[TestClass]
public sealed class ReportFormatterTest
{
[TestMethod]
public void Format()
{
var sut = new ReportFormatter();
var result = sut.Format(12345.67M);
Assert.AreEqual("12345.67", result);
}
}
This works perfectly fine. Lets even imagine that all our machines all have the same setup, and all are set to use the same regional settings. Great, nothing should ever break.
Until maybe Microsoft releases a patch to Windows that changes our regional settings to be "correct" - in fact, South Africa should be using a comma as a separator... even though none of us use this standard :D
So then it breaks our code, and our business rules that disagree with it.
Well, the good news is we can change the regional settings of the running thread, by changing its CultureInfo details. Here is a little utility class to do so:
public class TemporaryCultureSwitch : IDisposable
{
private readonly CultureInfo _originalCulture;
private readonly CultureInfo _originalUICulture;
public TemporaryCultureSwitch(CultureInfo cultureInfo)
{
_originalCulture = Thread.CurrentThread.CurrentCulture;
_originalUICulture = Thread.CurrentThread.CurrentUICulture;
Thread.CurrentThread.CurrentCulture = cultureInfo;
Thread.CurrentThread.CurrentUICulture = cultureInfo;
}
public TemporaryCultureSwitch(string cultureName) : this(new CultureInfo(cultureName)) { }
public void Dispose()
{
Thread.CurrentThread.CurrentCulture = _originalCulture;
Thread.CurrentThread.CurrentUICulture = _originalUICulture;
}
}
We can now update our test to be a bit more specific:
[TestMethod]
public void FormatShouldNotBeAffectedByCultureChanges()
{
var culture = new CultureInfo("en-ZA");
culture.NumberFormat.NumberDecimalSeparator = ",";
using (new TemporaryCultureSwitch(culture))
{
var sut = new ReportFormatter();
var result = sut.Format(12345.67M);
Assert.AreEqual("12345.67", result);
}
}
Now we have a test that will fail consistently! Time to fix the code. One way of doing this is realizing that there is an overload of Decimal.ToString that takes in a CultureInfo object. We actually can use the InvariantCulture as below:
public string Format(decimal value)
{
return value.ToString(CultureInfo.InvariantCulture);
}
The test passes and we now know for sure that regional settings won't affect our code.
Wednesday, January 25, 2017
Uninstall Windows Service using PowerShell
You can get a list of services using the Get-Service cmdlet, for example, to retrieve a list of all running services you could run:
Get-Service | Where-Object { $_.Status -eq "Running" }
You could even retrieve a specific service and start/stop it:
$service = Get-Service DemoService
$service.Start()
$service.Stop()
However, there is nothing to remove the service on this object.
We can also use GetWmiObject to do the same things:
$service = Get-WmiObject Win32_Service -Filter "name='DemoService'"
$service.StartService()
$service.StopService()
But this WMI object actually also exposes a delete functionality, which will mark the service to be deleted.
$service = Get-WmiObject Win32_Service -Filter "name='DemoService'"
$service.Delete()
If there are resources that are being held onto, it will only be deleted once they're freed up - whether it's the service that needs to gracefully shutdown still, or maybe the services manager snap-in (services.msc) has an open properties window open (I think that's happened to me before), and closing it then puts the delete through.
Get-Service | Where-Object { $_.Status -eq "Running" }
You could even retrieve a specific service and start/stop it:
$service = Get-Service DemoService
$service.Start()
$service.Stop()
However, there is nothing to remove the service on this object.
We can also use GetWmiObject to do the same things:
$service = Get-WmiObject Win32_Service -Filter "name='DemoService'"
$service.StartService()
$service.StopService()
But this WMI object actually also exposes a delete functionality, which will mark the service to be deleted.
$service = Get-WmiObject Win32_Service -Filter "name='DemoService'"
$service.Delete()
If there are resources that are being held onto, it will only be deleted once they're freed up - whether it's the service that needs to gracefully shutdown still, or maybe the services manager snap-in (services.msc) has an open properties window open (I think that's happened to me before), and closing it then puts the delete through.
Thursday, July 7, 2016
Updating NuGet extension on Visual Studio 2015
NuGet is pretty awesome, though for some reason the NuGet Package Manager for Visual Studio 2015 extension was re-done and every time I try to update it I get an error, and then the extension seems to not work when restarting Visual Studio.
Took quite a while to figure out why, but it seems that it's to do with not being able to uninstall the old version of the extension. Extensions are installed into the folder C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\Extensions (or similar depending on the VS version). Certain folders in this path relate to an extension per folder, those that look like randomly generated names specifically, as below:

Each time the NuGet extension tried to update, it would fail to remove the old installation, and then create a new folder for the 'upgrade'. If you tried to upgrade it a few times, you may have quite a few folders that contain the NuGet extension. When you restart VS it seems to have issues loading the extension because of this. Go through each of these to find those folders, e.g.:

Close Visual Studio, and then delete each of those folders specific to the NuGet extension. Then manually download the VSIX extension installer from the website, and install it outside of Visual Studio. Once complete, start up Visual Studio and the extension should be installed properly. Whether it works or not is another thing, it seems the GUI is quite buggy with this extension, so I prefer using the Package Manager Console.
Hope this helps someone, I've had to come back to doing this a few times, so it'll definitely help me in future I'm sure :D
Subscribe to:
Posts (Atom)