unit RGBSeparateUnit;
// PicViewer (c) J. Dempster, University of Strathclyde, 2003
// ----------------------------------------------------------
// RGB Separate : Splits RGB channels into separate grey scale stacks
// ----------------------------------------------------------
// 11.12.06

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ImageFile, StrUtils ;

type
  TRGBSeparateFrm = class(TForm)
    SaveRed: TImageFile;
    SaveGreen: TImageFile;
    SaveBlue: TImageFile;
    SourceGrp: TGroupBox;
    cbSource: TComboBox;
    bOK: TButton;
    bCancel: TButton;
    GroupBox1: TGroupBox;
    ckSaveRed: TCheckBox;
    ckSaveGreen: TCheckBox;
    ckSaveBlue: TCheckBox;
    procedure FormShow(Sender: TObject);
    procedure bOKClick(Sender: TObject);
    procedure bCancelClick(Sender: TObject);
  private
    { Private declarations }
    procedure SeparateRGBChannels ;
  public
    { Public declarations }
  end;

var
  RGBSeparateFrm: TRGBSeparateFrm;

implementation

uses PicViewMain, ViewUnit, maths ;

{$R *.dfm}

procedure TRGBSeparateFrm.FormShow(Sender: TObject);
// -------------------------------------
// Initialisation when form is displayed
// -------------------------------------
var
     i : Integer ;
begin

     // Get list of available image stacks
     cbSource.Clear ;
     for i :=  0 to High(MainFrm.ViewFrmsInUse) do if MainFrm.ViewFrmsInUse[i] then begin
         if MainFrm.ViewFrms[i].NumComponentsPerPixel = 3 then begin
            cbSource.Items.AddObject( MainFrm.ViewFrms[i].FileName, TObject(i)) ;
            end ;
         end ;
     cbSource.ItemIndex := 0 ;

     bOK.Enabled := True ;

     end;


procedure TRGBSeparateFrm.SeparateRGBChannels ;
// --------------------------------------
// Separate RGB channels into separate grey scale files
// --------------------------------------
var
     FileNameRed : String ;
     FileNameGreen : String ;
     FileNameBlue : String ;
     FileNameComb : String ;
     s : String ;

     i,j : Integer ;           // General counter
     iSource : Integer ;
     FrameNum : Integer ;    // Source frame counter

     NumPixelsPerFrame : Cardinal ;
     NumComponentsPerPixel : Cardinal ;
     NumComponentsPerFrame : Cardinal ;
     NumBytesPerPixel : Integer ;

     PRedBuf : PIntArray ;       // Red frame buffer pointer
     PGreenBuf : PIntArray  ;       // Green frame buffer pointer
     PBlueBuf : PIntArray  ;       // Blue frame buffer pointer
     PRGBBuf : PIntArray  ;       // RGB frame buffer pointer

begin

     // Source of image stacks to be merged
     iSource := Integer(cbSource.Items.Objects[cbSource.ItemIndex]) ;

     // Output file names
     FileNameRed := ChangeFileExt( MainFrm.ViewFrms[iSource].FileName, '.pic' ) ;
     FileNameRed := ANSIReplaceStr( FileNameRed, '.pic', ' (red).pic' ) ;
     FileNameGreen := ChangeFileExt( MainFrm.ViewFrms[iSource].FileName, '.pic' ) ;
     FileNameGreen := ANSIReplaceStr( FileNameGreen, '.pic', ' (green).pic' ) ;
     FileNameBlue := ChangeFileExt( MainFrm.ViewFrms[iSource].FileName, '.pic' ) ;
     FileNameBlue := ANSIReplaceStr( FileNameBlue, '.pic', ' (blue).pic' ) ;

     // Create combined name
     s := '(' ;
     if ckSaveRed.Checked then s := s + 'red ' ;
     if ckSaveGreen.Checked then s := s + 'green ' ;
     if ckSaveBlue.Checked then s := s + 'blue ' ;
     s := s + ').pic' ;
     FileNameComb := ChangeFileExt( MainFrm.ViewFrms[iSource].FileName, '.pic' ) ;
     FileNameComb := ANSIReplaceStr( FileNameComb, '.pic', s ) ;

     // Let user quit if merge file already exists
     if FileExists(FileNameRed) or
        FileExists(FileNameGreen) or
        FileExists(FileNameBlue) then begin
        if MessageDlg( 'RGB Separate: ' + FileNameComb + ' already exists! Overwrite them?',
           mtWarning, [mbYes,mbNo], 0 ) = mrNo then Exit ;
        end ;

     // Create red, green and blue output file

     if ckSaveRed.Checked then begin
        SaveRed.CreateFile( FileNameRed,
                            MainFrm.ViewFrms[iSource].FrameWidth,
                            MainFrm.ViewFrms[iSource].FrameHeight,
                            MainFrm.ViewFrms[iSource].PixelDepth,
                            1,
                            False ) ;
        SaveRed.XResolution := MainFrm.ViewFrms[iSource].XResolution ;
        SaveRed.YResolution := MainFrm.ViewFrms[iSource].YResolution ;
        SaveRed.ZResolution := MainFrm.ViewFrms[iSource].ZResolution ;
        SaveRed.TResolution := MainFrm.ViewFrms[iSource].TResolution ;
        SaveRed.ResolutionUnit := MainFrm.ViewFrms[iSource].PixelUnits ;
        end ;

     if ckSaveGreen.Checked then begin
        SaveGreen.CreateFile( FileNameGreen,
                              MainFrm.ViewFrms[iSource].FrameWidth,
                              MainFrm.ViewFrms[iSource].FrameHeight,
                              MainFrm.ViewFrms[iSource].PixelDepth,
                              1,
                              False ) ;
        SaveGreen.XResolution := MainFrm.ViewFrms[iSource].XResolution ;
        SaveGreen.YResolution := MainFrm.ViewFrms[iSource].YResolution ;
        SaveGreen.ZResolution := MainFrm.ViewFrms[iSource].ZResolution ;
        SaveGreen.TResolution := MainFrm.ViewFrms[iSource].TResolution ;
        SaveGreen.ResolutionUnit := MainFrm.ViewFrms[iSource].PixelUnits ;
        end ;

     if ckSaveBlue.Checked then begin
        SaveBlue.CreateFile( FileNameBlue,
                             MainFrm.ViewFrms[iSource].FrameWidth,
                             MainFrm.ViewFrms[iSource].FrameHeight,
                             MainFrm.ViewFrms[iSource].PixelDepth,
                             1,
                             False ) ;
        SaveBlue.XResolution := MainFrm.ViewFrms[iSource].XResolution ;
        SaveBlue.YResolution := MainFrm.ViewFrms[iSource].YResolution ;
        SaveBlue.ZResolution := MainFrm.ViewFrms[iSource].ZResolution ;
        SaveBlue.TResolution := MainFrm.ViewFrms[iSource].TResolution ;
        SaveBlue.ResolutionUnit := MainFrm.ViewFrms[iSource].PixelUnits ;
        end ;

     NumPixelsPerFrame := MainFrm.ViewFrms[iSource].FrameWidth*
                          MainFrm.ViewFrms[iSource].FrameHeight ;
     NumComponentsPerFrame := NumPixelsPerFrame*MainFrm.ViewFrms[iSource].NumComponentsPerPixel ;
     NumBytesPerPixel := ((MainFrm.ViewFrms[iSource].PixelDepth-1) div 8) + 1 ;

     // Close form (if output file is on display)
     MainFrm.CloseViewFrm(FileNameRed);
     MainFrm.CloseViewFrm(FileNameGreen);
     MainFrm.CloseViewFrm(FileNameBlue);

     // Allocate frame buffers
     GetMem( PRedBuf, NumComponentsPerFrame*4 ) ;
     GetMem( PGreenBuf, NumComponentsPerFrame*4 ) ;
     GetMem( PBlueBuf, NumComponentsPerFrame*4 ) ;
     GetMem( PRGBBuf, NumComponentsPerFrame*4 ) ;

     try

        for FrameNum := 1 to MainFrm.ViewFrms[iSource].NumFrames do begin

            // Load frame from RGB file
            MainFrm.ViewFrms[iSource].LoadFrame( FrameNum, PRGBBuf ) ;

            // Copy RGB into separate buffers
            j := 0 ;
            for i := 0 to NumPixelsPerFrame-1 do begin
                PRedBuf^[i] := PRGBBuf^[j] ;
                Inc(j) ;
                PGreenBuf^[i] := PRGBBuf^[j] ;
                Inc(j) ;
                PBlueBuf^[i] := PRGBBuf^[j] ;
                Inc(j) ;
                end ;

            // Save images to destination
            if ckSaveRed.Checked then SaveRed.SaveFrame32( FrameNum, PRedBuf ) ;
            if ckSaveGreen.Checked then SaveGreen.SaveFrame32( FrameNum, PGreenBuf ) ;
            if ckSaveBlue.Checked then SaveBlue.SaveFrame32( FrameNum, PBlueBuf ) ;

            // Report progress
            MainFrm.StatusBar.SimpleText := format(
            'Merge to RGB: Frame %.4d/%.4d to %s',
            [FrameNum,MainFrm.ViewFrms[iSource].NumFrames,ExtractFileName(FileNameComb)] ) ;

            if bOK.Enabled then Break ;
            Application.ProcessMessages ;

            end ;

        // Close output files
        if ckSaveRed.Checked then SaveRed.CloseFile ;
        if ckSaveGreen.Checked then SaveGreen.CloseFile ;
        if ckSaveBlue.Checked then SaveBlue.CloseFile ;

        MainFrm.StatusBar.SimpleText := format(
        'Merge to RGB: File: %s etc. created',
        [ExtractFileName(FileNameComb)] ) ;

        // Display new red, green and blue files
        if ckSaveRed.Checked then MainFrm.CreateNewViewFrm( FileNameRed ) ;
        if ckSaveGreen.Checked then MainFrm.CreateNewViewFrm( FileNameGreen ) ;
        if ckSaveBlue.Checked then MainFrm.CreateNewViewFrm( FileNameBlue ) ;

     finally
        FreeMem( PRedBuf ) ;
        FreeMem( PGreenBuf ) ;
        FreeMem( PBlueBuf ) ;
        FreeMem( PRGBBuf ) ;
        end ;

     end ;


procedure TRGBSeparateFrm.bOKClick(Sender: TObject);
// -------------------------------------
// Copy RGB channels into separate files
// -------------------------------------
begin
     // Prevent multiple activation
     bOK.Enabled := False ;
     Application.ProcessMessages ;

     // Merge from separate files or frames
     SeparateRGBChannels ; ;

     bOK.Enabled := True ;

     end ;

procedure TRGBSeparateFrm.bCancelClick(Sender: TObject);
//  ------------------------------
// Cancel separation / close form
// ------------------------------
begin
     bOK.Enabled := True ;
     end;

end.
