вівторок, 26 травня 2020 р.

QRCode\BarCode in your C#\Xamarin application

Below is really working C#\Xamarin code, tested. You'll be need to install ZXing.Mobile packet. I realised it by adding DependencyService to my project.

OK. Thanks to the posts above, I managed to get this working so I thought I'd post code for anyone having issues in the future. Remember, this is solely around the display of a barcode NOT the scanning!

I added ZXing.Net.Mobile to my Droid and iOS projects. I didn't need to add it to my core Forms project.

In my core Forms project I had an image in XAML:

<Image Grid.Row="13" Grid.ColumnSpan="2" Source="{Binding BarcodeImageSource}" HorizontalOptions="Center" WidthRequest="300" HeightRequest="130"/>

On my view model I had:

public ImageSource BarcodeImageSource { get;set;}
....
// this will set the image source for the BarcodeImageSource property which the Image in XAML will pick up 
var stream = this.barcodeService.ConvertImageStream(result.CardId);
this.BarcodeImageSource =  ImageSource.FromStream(() => {return stream; });

Ok that bit of code 'this.barcodeService.ConvertImageStream(result.CardId);' had to use dependency injection to have Droid and iOS specific code. The ZXing code is the same in both cases. It's actually the code for writing the bitmap to a stream that is platform specific.

So I have my interface:

using System;
using System.IO;

namespace MyApp.Services
{
  public interface IBarcodeService 
  {   
      Stream ConvertImageStream(string text, int width = 300, int height=130);    
  }
}

Then Android implementation:

using Android.Graphics;
using MyApp.Services
using System;
using System.IO;
using ZXing.Mobile;

namespace MyApp.Android
{
  public class BarcodeService : IBarcodeService
  {
      public Stream ConvertImageStream(string text,int width = 300, int height=130)
      {
          var barcodeWriter = new ZXing.Mobile.BarcodeWriter {
                      Format = ZXing.BarcodeFormat.CODE_39,
                      Options = new ZXing.Common.EncodingOptions {
                          Width = width,
                          Height = height,
                                              Margin = 10
                      }
                  };

          barcodeWriter.Renderer = new ZXing.Mobile.BitmapRenderer();
          var bitmap = barcodeWriter.Write(text);
          var stream = new MemoryStream();
          bitmap.Compress(Bitmap.CompressFormat.Png,100,stream);  // this is the diff between iOS and Android
          stream.Position = 0;
          return stream;
      }
  }
}

And the iOS implementation.

using System;
using System.Drawing;
using System.IO;
using Xamarin.Forms;
using MyApp.Services;
using UIKit;
using CoreGraphics;
using ZXing.Mobile;

namespace MyApp.iOS
{
  public class BarcodeService : IBarcodeService
  {
      public Stream ConvertImageStream(string text,int width = 300, int height=130)
      {
          var barcodeWriter = new ZXing.Mobile.BarcodeWriter {
                      Format = ZXing.BarcodeFormat.CODE_39,
                      Options = new ZXing.Common.EncodingOptions {
                          Width = width,
                          Height = height,
                                              Margin = 10
                      }
                  };
          barcodeWriter.Renderer = new ZXing.Mobile.BitmapRenderer();
          var bitmap = barcodeWriter.Write(text);
          var stream = bitmap.AsPNG().AsStream(); // this is the difference 
          stream.Position = 0;

          return stream;
      }
  }
}

понеділок, 4 травня 2020 р.

How to replace text in batch file

First part. What if you want to replace some text in your source code based on different settings (f.e., when CI uses)? I had a situation, when host and database were hardcoded by another person as consts and they have stay there. You may move consts into ini file (what I did some time later), but you also are able to parse your source file. Below I'll show how to do it using bat file.

So code below searches consts with the names SQL_SERVER_NAME and DATABASE_NAME and replaces them with the replace_SQL_SERVER_NAME and replace_DATABASE_NAME lines. Now you know, that this code has a limitation: it replaces whole lines. But it works, that it.

REM database.php update START
@echo off &setlocal
setlocal enableDelayedExpansion
:: Lines below has been searched
set "const=const"
set "SQL_SERVER_NAME=SQL_SERVER_NAME"
set "DATABASE_NAME=DATABASE_NAME"
:: Lines below has been replaced with the "search_xxx"
:: !!!-------------------- UPDATE VARIABLES BELOW --------------------!!!
set "replace_SQL_SERVER_NAME= const SQL_SERVER_NAME = "SERVER\NEW_SERVER_NAME";"
set "replace_DATABASE_NAME= const DATABASE_NAME = "NEW_DATABASE_NAME";"
:: !!!-------------------- UPDATE VARIABLES ABOVE --------------------!!!
:: File to be processed
set "textfile=database.php"
:: Temporary file
set "newfile=database_tmp.php"
:: Define LF to contain a linefeed character
set "signExclamation=^!"
:: Define LF to contain a linefeed character
set ^"LF=^

^"
:: The empty line above is critical
::(for /f "delims=" %%i in (%textfile%) do (
(for /f "USEBACKQ tokens=1,2 delims=^!^" %%i in (`type %textfile% ^| find /V /N ""`) do (
    set "part1=%%i"
 set "part2=%%j"
 :: Save ! sign
 if "!part2!"=="" (
  set "line=!part1!!part2!"
 ) else (
  set "line=!part1!!signExclamation!!part2!"
 )

 :: Save an empty lines
 set "line=!line:*]=!"

 set "str1="
 set "str2="
 :: Left trim the line to compare with the "search"
 for /f "tokens=1,2 delims=  " %%a in ("!line!") do (
  set "str1=%%a"
  set "str2=%%b"
 )

 :: Replace consts
 set "str=!line!"
 if "!str1!"=="!const!" (
  if "!str2!"=="!SQL_SERVER_NAME!" (
   set "str=!replace_SQL_SERVER_NAME!"
  ) else (
   if "!str2!"=="!DATABASE_NAME!" (
    set "str=!replace_DATABASE_NAME!"
   )
  )
 )

    echo(!str!)
)>"%newfile%"
del %textfile%
rename %newfile%  %textfile%
endlocal
@echo on
REM database.php update END

You are welcome to test code above. Just create database.php file, add there 2 lines:
 const SQL_SERVER_NAME = "OLD_SERVER_NAME";
 const DATABASE_NAME = "OLD_DATABASE_NAME";
Create *.bat file in the same folder and run it.

Second part. What if you want to insert some code into your f.e. web.config file in production?

REM web.config update START
@echo off &setlocal
setlocal enableDelayedExpansion
:: Line below has been searched
set "search=</system.webServer>"
:: Line below has been added before the "search"
set "replace=        <urlCompression doStaticCompression="false" doDynamicCompression="false" />"
:: File to be processed
set "textfile=web.config"
:: Temporary file
set "newfile=web_tmp.config"
:: Define LF to contain a linefeed character
set ^"LF=^

^"
:: The empty line above is critical
(for /f "delims=" %%i in (%textfile%) do (
    set "line=%%i"
 :: Left trim the line to compare with the "search"
 for /f "tokens=* delims= " %%a in ("!line!") do set "str=%%a"
 :: Add line before the "search"
 if "!str!"=="!search!" (
  set "str=!replace!!LF!"
 ) else (
  set "str="
 )
    echo(!str!!line!))>"%newfile%"
del %textfile%
rename %newfile%  %textfile%
endlocal
@echo on
REM web.config update END

Well, it just finds search in in your web.config file and inserts replace before it. You know how to test.