ImageEn for Delphi and C++ Builder ImageEn for Delphi and C++ Builder

 

ImageEn Forum
Profile    Join    Active Topics    Forum FAQ    Search this forumSearch
Forum membership is Free!  Click Join to sign-up
Username:
Password:
Save Password
Forgot your Password?

 All Forums
 ImageEn Library for Delphi, C++ and .Net
 ImageEn and IEvolution Support Forum
 Solution: Storing Twain Params
 New Topic  Reply to Topic
Author Previous Topic Topic Next Topic  

Elemental

USA
56 Posts

Posted - Mar 26 2014 :  10:38:31  Show Profile  Reply
I wrote a class helper in Delphi XE5 for the TIETwainParams class. It loads and stores certain settings from and to a file of your choice. You can specify any extension you like, but it will be plain text regardless.

Note that this is not a new class that inherits from TIETwainParams, but a class helper. This is nice because various ImageEn components and objects already have properties of this type, and an overridden class would not help much there. So, whenever you have access to an instance of TIETwainParams from the ImageEn product, you can call these new methods. Note that Delphi's Code Insight feature will show these as available methods, Error Insight will be OK with them, and the compiler will be happy, too.


unit uImageEnTwain;

interface

uses ietwain, System.SysUtils;

type
  TIETwainHelper = class helper for TIETwainParams
  protected
    const StoredSettingsProperties: array[0..36] of String = (
      'SelectedSource',
      'AcceptedImages',
      'AcquireFrameEnabled',
      'AcquireFrameLeft',
      'AcquireFrameRight',
      'AcquireFrameTop',
      'AcquireFrameBottom',
      'AutoBorderDetection',
      'AutoDeskew',
      'AutoDiscardBlankPages',
      'AutoScan',
      'BitDepth', //(TIEIntegerList)
      'AutoBright',
      'Brightness', //(TIEDoubleList)
      'BufferedTransfer',
      'Contrast', //(TIEDoubleList)
      'DuplexSupported',
      'DuplexEnabled',
      'AutoFeed',
      'FeederSupported',
      'FeederEnabled',
      'Gamma',
      'Highlight',
      'Orientation', //(TIEDoubleList)
      'PaperDetectable',
      'PhysicalWidth',
      'PhysicalHeight',
      'PixelType', // (TIEIntegerList)
      'AutoRotate',
      'Rotation', //(TIEDoubleList)
      'Shadow',
      'Threshold', // (TIEDoubleList)
      'VisibleDialog',
      'XResolution', // (TIEDoubleList)
      'YResolution', // (TIEDoubleList)
      'XScaling', // (TIEDoubleList)
      'YScaling' // (TIEDoubleList)
    );
  public
    function SaveSettingsToFile( FileName: TFileName ): Boolean;
    function LoadSettingsFromFile( FileName: TFileName ): Boolean;
  end;

implementation

uses System.Rtti, System.TypInfo, System.Variants, System.Classes, System.IOUtils, hyieutils, System.StrUtils;

{ TIETwainHelper }

function TIETwainHelper.LoadSettingsFromFile(FileName: TFileName): Boolean;
var
  slPropVals: TStringList;
  iLastSource: Integer;
  rcRttiContext: TRttiContext;
  rtThisType: TRttiType;
  iPropertyIndex: Integer;
  sPropName: String;
  rpThisProperty: TRttiProperty;
  tvThisValue: TValue;
  varThisValue: Variant;
begin
  if TFile.Exists( FileName ) then
  begin
    slPropVals := TStringList.Create;
    try
      begin
        slPropVals.LoadFromFile( FileName );
        iLastSource := StrToIntDef( slPropVals.Values[ 'SelectedSource' ], -1 );
        SelectedSource := iLastSource;
        rcRttiContext := TRttiContext.Create;
        rtThisType := rcRttiContext.GetType( ClassType );
        for iPropertyIndex := Low( StoredSettingsProperties ) to High( StoredSettingsProperties ) do
        begin
          sPropName := StoredSettingsProperties[ iPropertyIndex ];
          rpThisProperty := rtThisType.GetProperty( sPropName );
          if Assigned( rpThisProperty ) then
            try
              tvThisValue := rpThisProperty.GetValue( Self );
              if tvThisValue.IsObject then
                if tvThisValue.AsObject is TIEDoubleList then
                begin
                  if slPropVals.IndexOfName( sPropName + '.CurrentValue' ) > -1 then
                    TIEDoubleList(tvThisValue.AsObject).CurrentValue :=
                      StrToFloat( slPropVals.Values[ sPropName + '.CurrentValue' ] );
                end
                else
                  if tvThisValue.AsObject is TIEIntegerList then
                  begin
                    if slPropVals.IndexOfName( sPropName + '.CurrentValue' ) > -1 then
                      TIEIntegerList(tvThisValue.AsObject).CurrentValue :=
                        StrToInt( slPropVals.Values[ sPropName + '.CurrentValue' ] );
                  end
                  else
                    if slPropVals.IndexOfName( sPropName ) > -1 then
                    begin
                      if rpThisProperty.IsWritable then
                      begin
                        varThisValue := slPropVals.Values[ sPropName ];
                        tvThisValue.FromVariant( varThisValue );
                        rpThisProperty.SetValue( Self, tvThisValue );
                      end;
                    end;
            except
              on E: Exception do
                raise Exception.CreateFmt( 'Error reading TWAIN property %s from file %s',
                  [ sPropName, FileName ] );
            end
        end;
      end;
    finally
      slPropVals.Free;
    end;
    Update;
    Result := True;
  end
  else
    Result := False;
end;

function TIETwainHelper.SaveSettingsToFile(FileName: TFileName): Boolean;
var
  slPropVals: TStringList;
  iSourceIndex: Integer;
  rcRttiContext: TRttiContext;
  rtThisType: TRttiType;
  iPropertyIndex: Integer;
  sPropName: String;
  rpThisProperty: TRttiProperty;
  tvThisValue: TValue;
  varThisValue: Variant;
  sThisValue: String;
  sParentDirectory: TFileName;
  ItemIndex: Integer;
begin
  slPropVals := TStringList.Create;
  try
    for iSourceIndex := 0 to SourceCount - 1 do
      slPropVals.Values[ 'Source' + IntToStr( iSourceIndex ) ] := String(SourceName[ iSourceIndex ]);
    slPropVals.Values[ 'GetDefaultSource' ] := IntToStr( GetDefaultSource );
    rcRttiContext := TRttiContext.Create;
    rtThisType := rcRttiContext.GetType( ClassType );
    for iPropertyIndex := Low( StoredSettingsProperties ) to High( StoredSettingsProperties ) do
    begin
      sPropName := StoredSettingsProperties[ iPropertyIndex ];
      rpThisProperty := rtThisType.GetProperty( sPropName );
      if Assigned( rpThisProperty ) and rpThisProperty.IsReadable then
        try
          tvThisValue := rpThisProperty.GetValue( Self );
          if tvThisValue.IsInstanceOf( TIEDoubleList ) then
          begin
            sThisValue := FormatFloat( '0.0', TIEDoubleList(tvThisValue.AsObject).CurrentValue );
            slPropVals.Values[ sPropName + '.CurrentValue' ] := sThisValue;
            sThisValue := FormatFloat( '0.0', TIEDoubleList(tvThisValue.AsObject).RangeMin );
            slPropVals.Values[ sPropName + '.RangeMin' ] := sThisValue;
            sThisValue := FormatFloat( '0.0', TIEDoubleList(tvThisValue.AsObject).RangeStep );
            slPropVals.Values[ sPropName + '.RangeStep' ] := sThisValue;
            sThisValue := FormatFloat( '0.0', TIEDoubleList(tvThisValue.AsObject).RangeMax );
            slPropVals.Values[ sPropName + '.RangeMax' ] := sThisValue;
            sThisValue := '';
            for ItemIndex := 0 to TIEDoubleList(tvThisValue.AsObject).Count - 1 do
            begin
              if ItemIndex > 0 then
                sThisValue := sThisValue + ',';
              sThisValue := sThisValue +
                FormatFloat( '0.0', TIEDoubleList(tvThisValue.AsObject)[ ItemIndex ] );
            end;
            slPropVals.Values[ sPropName + '.Items' ] := sThisValue;
          end
          else
            if tvThisValue.IsInstanceOf( TIEIntegerList ) then
            begin
              sThisValue := IntToStr( TIEIntegerList(tvThisValue.AsObject).CurrentValue );
              slPropVals.Values[ sPropName + '.CurrentValue' ] := sThisValue;
              sThisValue := IntToStr( TIEIntegerList(tvThisValue.AsObject).RangeMin );
              slPropVals.Values[ sPropName + '.RangeMin' ] := sThisValue;
              sThisValue := IntToStr( TIEIntegerList(tvThisValue.AsObject).RangeStep );
              slPropVals.Values[ sPropName + '.RangeStep' ] := sThisValue;
              sThisValue := IntToStr( TIEIntegerList(tvThisValue.AsObject).RangeMax );
              slPropVals.Values[ sPropName + '.RangeMax' ] := sThisValue;
              sThisValue := '';
              for ItemIndex := 0 to TIEIntegerList(tvThisValue.AsObject).Count - 1 do
              begin
                if ItemIndex > 0 then
                  sThisValue := sThisValue + ',';
                sThisValue := sThisValue +
                  IntToStr( TIEIntegerList(tvThisValue.AsObject)[ ItemIndex ] );
              end;
              slPropVals.Values[ sPropName + '.Items' ] := sThisValue;
            end
            else
            begin
              varThisValue := tvThisValue.AsVariant;
              sThisValue := VarToStr( varThisValue );
              slPropVals.Values[ sPropName ] := sThisValue;
            end;
        except
          on E: Exception do
            raise Exception.CreateFmt( 'Error writing TWAIN property %s to file %s',
              [ sPropName, FileName ] );
        end;
    end;

    sParentDirectory := TPath.GetDirectoryName( FileName );
    if ( sParentDirectory <> '' ) and
      TPath.HasValidPathChars( sParentDirectory, False ) and
      not TDirectory.Exists( sParentDirectory ) then
      TDirectory.CreateDirectory( sParentDirectory );
    slPropVals.SaveToFile( FileName );

    Result := True;
  finally
    slPropVals.Free;
  end;
end;

end.


"Roj"

Elemental

USA
56 Posts

Posted - Mar 26 2014 :  13:55:09  Show Profile  Reply
I apologize, but the code that read the parameters was wrong, where a certain else statement would never be reached.


function TIETwainHelper.LoadSettingsFromFile(FileName: TFileName): Boolean;
var
  slPropVals: TStringList;
  iLastSource: Integer;
  rcRttiContext: TRttiContext;
  rtThisType: TRttiType;
  iPropertyIndex: Integer;
  sPropName: String;
  rpThisProperty: TRttiProperty;
  tvThisValue: TValue;
  varThisValue: Variant;
begin
  if TFile.Exists( FileName ) then
  begin
    slPropVals := TStringList.Create;
    try
      begin
        slPropVals.LoadFromFile( FileName );
        iLastSource := StrToIntDef( slPropVals.Values[ 'SelectedSource' ], -1 );
        SelectedSource := iLastSource;
        rcRttiContext := TRttiContext.Create;
        rtThisType := rcRttiContext.GetType( ClassType );
        for iPropertyIndex := Low( StoredSettingsProperties ) to High( StoredSettingsProperties ) do
        begin
          sPropName := StoredSettingsProperties[ iPropertyIndex ];
          if sPropName <> 'SelectedSource' then
          begin
            rpThisProperty := rtThisType.GetProperty( sPropName );
            if Assigned( rpThisProperty ) then
              try
                tvThisValue := rpThisProperty.GetValue( Self );
                if tvThisValue.IsObject then
                begin
                  if tvThisValue.AsObject is TIEDoubleList then
                  begin
                    if slPropVals.IndexOfName( sPropName + '.CurrentValue' ) > -1 then
                      TIEDoubleList(tvThisValue.AsObject).CurrentValue :=
                        StrToFloat( slPropVals.Values[ sPropName + '.CurrentValue' ] );
                  end
                  else
                    if tvThisValue.AsObject is TIEIntegerList then
                    begin
                      if slPropVals.IndexOfName( sPropName + '.CurrentValue' ) > -1 then
                        TIEIntegerList(tvThisValue.AsObject).CurrentValue :=
                          StrToInt( slPropVals.Values[ sPropName + '.CurrentValue' ] );
                    end
                end
                else
                  if slPropVals.IndexOfName( sPropName ) > -1 then
                    if rpThisProperty.IsWritable then
                    begin
                      varThisValue := slPropVals.Values[ sPropName ];
                      tvThisValue.FromVariant( varThisValue );
                      rpThisProperty.SetValue( Self, tvThisValue );
                    end;
            except
              on E: Exception do
                raise Exception.CreateFmt( 'Error reading TWAIN property %s from file %s',
                  [ sPropName, FileName ] );
            end;
          end;
        end;
      end;
    finally
      slPropVals.Free;
    end;
    Result := True;
  end
  else
    Result := False;
end;

Go to Top of Page

xequte

38514 Posts

Posted - Apr 03 2014 :  17:42:17  Show Profile  Reply
Thanks Roj,

Avaialble as a unit here with some modifications to make it more similar to ImageEn styling:

www.imageen.com/files/Other/iexTwainHelperFunctions.pas

Note:
- Not tested
- Requires Delphu/C++ 2010 or newer

Nigel
Xequte Software
www.xequte.com
nigel@xequte.com
Go to Top of Page

Elemental

USA
56 Posts

Posted - Aug 24 2015 :  18:14:50  Show Profile  Reply
Recently, one of my primary users started to report that my ImageEn program wasn't remembering her choice for Duplex scanning. My program shows her a TWAIN dialog, she makes the change, clicks OK and ImageEn doesn't realize it. I verified that her ImageEn program could pull other settings out of the TWAIN dialog such as resolution, color depth, and page size, but it doesn't realize when she chooses Duplex. This is a Canon DR-9080C scanner.

Now, there IS the option to Scan Both Sides Ignoring Blank Pages. She can use that, but sometimes she wants true Duplex where it keeps blank pages. ImageEn used to be able to know which scanning option she chose, but it doesn't anymore. Without any changes on my end in the past few months, it doesn't work anymore. Any ideas?
Go to Top of Page

xequte

38514 Posts

Posted - Aug 24 2015 :  23:04:47  Show Profile  Reply
So it worked previously in ImageEn on her system then it stopped working? Did she install a newer driver of firmware for the scanner?



Nigel
Xequte Software
www.xequte.com
nigel@xequte.com
Go to Top of Page

Elemental

USA
56 Posts

Posted - Aug 25 2015 :  14:48:13  Show Profile  Reply
The executable was last modified in May 2015, so I believe it's using ImageEn 6.0.0. I have deployed a temporary version of my program using 6.0.1, but nothing changed.

I wanted to verify what we're supposed to do after setting ShowSettingsOnly to True and calling Acquire. It doesn't seem that the user's settings actually change the properties until I call Update. That's what I have to do, right? The documentation doesn't really say that; it says that Update validates the current parameters against what the scanner supports.

One thought I had was that it was the fault of a Windows Update. One such update was KB2952664, which was a compatibility update. It updates a file called imagingprovider.dll which is not in a standard Windows directory. I don't know if that had anything to do with anything.
Go to Top of Page

xequte

38514 Posts

Posted - Aug 27 2015 :  00:03:31  Show Profile  Reply
Hi

You should not need to call Update after acquire, because properties such as AcquireParams.DuplexEnabled will automatically read the current Twain capabilities.



Nigel
Xequte Software
www.xequte.com
nigel@xequte.com
Go to Top of Page
  Previous Topic Topic Next Topic  
 New Topic  Reply to Topic
Jump To: