{

   This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
}
unit Ufrmwork_saveas;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Ufrmworkbase, StdCtrls, UBrowserListView, Mask, Spin;

type
  TWorkThread = class;

  Tfrmwork_saveas = class(Tfrmworkbase)
    ComboBox1: TComboBox;
    Edit1: TEdit;
    Label2: TLabel;
    Label1: TLabel;
    GroupBox1: TGroupBox;
    CheckBox1: TCheckBox;
    Label11: TLabel;
    SpinEdit1: TSpinEdit;
    Label12: TLabel;
    SpinEdit2: TSpinEdit;
    TypeCombo: TComboBox;
    Label14: TLabel;
    Label13: TLabel;
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure ComboBox1Change(Sender: TObject);
  private
    { Private declarations }
    WorkThread:TWorkThread;

    procedure OkSeleted; override;
    procedure CancelSeleted; override;
    procedure WorkThreadOnprogress(Sender:TObject;
      totcount,currentcount:integer; msg:string; iserror:boolean);
    procedure WorkThreadOnTerminate(sender:tobject);
  public
    { Public declarations }
  end;

  TWorkThread = class(TThread)
  private
    totcount,currentcount:integer;
    FOnprogress:TOnprogress;
    ExistMethod:integer;
    noanswer:boolean;
    currentfilename:string;
    progressmsg:string;

    procedure savefile(data:PThumbImage;dest:string);
    procedure fileexistproc;
    procedure proc_onprogress;
  protected
    procedure Execute; override;
  public
    workselect:tworkselect;
    extselectidx:integer;
    prefix,path:string;
    resize:boolean;
    resize_width,resize_height:integer;
    resize_method:integer;
    constructor CreateThread;
    destructor Destroy; override;
  published
    property Onprogress:TOnprogress read FOnprogress write FOnprogress;
  end;


implementation

uses FreeBitmap, FreeImage, FreeUtils, Ufunction, Uconfig,
  UfrmMain, UExistMsg, Ufrmsaveopt;
{$R *.dfm}

{TWorkThread}
constructor TWorkThread.CreateThread;
begin
  FreeOnTerminate:=false;
  noanswer:=false;
  totcount:=0;
  currentcount:=0;
  inherited Create(true);
end;

destructor TWorkThread.Destroy;
begin
  inherited Destroy;
end;

function makefilename(name,prefix:string):string;
var
  s,s1:string;
begin
  s:=sysutils.ExtractFileName(name);
  s1:=sysutils.ExtractFileExt(name);
  s:=sysutils.StringReplace(s,s1,'',[rfReplaceAll]);
  result:=s+prefix+s1;
end;

procedure TWorkThread.Execute;
var
  i:integer;
  PThumbImage1:PThumbImage;
begin
try try
  case self.workselect of
    wscurrent:begin
      totcount:=1;
      currentcount:=1;
      savefile(currentimage,path);
    end;
    wslistselect,wslistall:begin
      for i:=0 to frmmain.listview1.Items.Count-1 do
        if (workselect=wslistall) or (frmmain.listview1.Items[i].Selected) then
          if PThumbImage(frmmain.listview1.Items[i].Data).imagetype<>itfolder then
             inc(totcount);

      currentcount:=0;
      for i:=0 to frmmain.listview1.Items.Count-1 do
        if (workselect=wslistall) or (frmmain.listview1.Items[i].Selected) then begin
          if self.Terminated then exit;
          PThumbImage1:=PThumbImage(frmmain.listview1.Items[i].Data);
          if PThumbImage1.imagetype=itfolder then continue;
          inc(currentcount);
          savefile(PThumbImage1,
             path+makefilename(PThumbImage1.name,prefix));
        end;
    end;
  end;
  except
    on E: Exception do begin
      progressmsg:=E.Message;
      Synchronize(proc_onprogress);
    end;
  end;
finally
end;
end;

procedure TWorkThread.fileexistproc;
var
  frmExistMsg:TfrmExistMsg;
begin
  frmExistMsg:=TfrmExistMsg.Create(frmworkbase);
  frmExistMsg.Label1.Caption:=
     format('[%s] 파일이 존재합니다.',[ExtractFileName(currentfilename)]);
  frmExistMsg.ShowModal;
  frmExistMsg.Free;
end;

procedure TWorkThread.savefile(data:PThumbImage;dest:string);
var
  s,ext:string;
  FBitmap:TFreeWinBitmap;
  w,h,NewWidth,NewHeight:integer;
  FreeMemoryIO1:TFreeMemoryIO;
  stream:tmemorystream;
  flag:boolean;
begin
  if workselect<>wscurrent then begin
    ext:=FIU_GetSelectExt(extselectidx+1);
    dest:=sysutils.ChangeFileExt(dest,ext);
  end;

  if sysutils.FileExists(dest) then begin
    currentfilename:=dest;
    if existnoanswer=false then
       self.Synchronize(fileexistproc);
    case config.c_existmethod of
      0:dest:=makeuniqfilename(dest);
      1:exit;
    end;
  end;

  FBitmap:=TFreeWinBitmap.Create;
  stream:=tmemorystream.Create;
  try
    if workselect=wscurrent then begin
      frmmain.imgview321.Bitmap.SaveToStream(stream);
      FreeMemoryIO1:=TFreeMemoryIO.Create(stream.Memory,stream.Size);
      try
        if FBitmap.LoadFromMemory(FreeMemoryIO1)=false then begin
          progressmsg:=format('%s 파일을 읽을수 없습니다.',[ExtractFileName(data.name)]);
          Synchronize(proc_onprogress);
          exit;
        end;
      finally
        FreeMemoryIO1.Free;
      end;
    end else begin
      if FBitmap.Load(data.name)=false then begin
        progressmsg:=format('%s 파일을 읽을수 없습니다.',[ExtractFileName(data.name)]);
        Synchronize(proc_onprogress);
        exit;
      end;
    end;

    if resize then begin
      w:=FBitmap.GetWidth;
      h:=FBitmap.GetHeight;
      if (resize_width>0) and (resize_height=0) then begin
        NewWidth:=resize_width;
        NewHeight:=Round(NewWidth * h / w);
      end else if (resize_width=0) and (resize_height>0) then begin
        NewHeight:=resize_height;
        NewWidth:=Round(NewHeight * w / h);
      end else if (resize_width>0) and (resize_height>0) then begin
        NewHeight:=resize_height;
        NewWidth:=resize_width;
      end else begin
        NewHeight:=h;
        NewWidth:=w;
      end;
      FBitmap.Rescale(NewWidth,NewHeight,TFreeStretchFilter(self.resize_method));
    end;

    if comparetext(ExtractFileExt(dest),'.gif')=0 then begin
      if FBitmap.IsTransparent then
        FBitmap.SetTransparentBg(nil);
      FBitmap.ConvertTo24Bits;
      FBitmap.ColorQuantize(FIQ_WUQUANT);
    end;

    flag:=FBitmap.Save(dest,selectsaveflag);
    if flag=false then begin
      if FBitmap.IsTransparent then
        FBitmap.SetTransparentBg(nil);
      FBitmap.ConvertTo24Bits;
      flag:=FBitmap.Save(dest,selectsaveflag);
    end;
    if flag=false then begin
      progressmsg:=format('%s 저장에 실패했습니다.',[ExtractFileName(dest)]);
      Synchronize(proc_onprogress);
      exit;
    end;
  finally
    FBitmap.Free;
    stream.Free;
  end;

  progressmsg:=ExtractFileName(dest);
  Synchronize(proc_onprogress);
end;

procedure TWorkThread.proc_onprogress;
begin
  if assigned(FOnprogress) then
    FOnprogress(self,totcount,currentcount,progressmsg,false);
end;

{Tfrmwork_saveas}
procedure Tfrmwork_saveas.FormCreate(Sender: TObject);
var
  strlist:tstringlist;
  i:integer;
begin
  inherited;
  strlist:=tstringlist.Create;
  try
    SplitString(FIU_GetAllFilters3,strlist,'^');
    for i:=0 to strlist.Count-1 do begin
      ComboBox1.Items.Add(strlist.Strings[i])
    end;
    if ComboBox1.Items.Count>config.c_lastselfiletype then
      ComboBox1.ItemIndex:=config.c_lastselfiletype;
    ComboBox1Change(nil);
  finally
    strlist.Free;
  end;
  self.TypeCombo.ItemIndex:=config.c_resize_method;
end;

procedure Tfrmwork_saveas.OkSeleted;
var
  s,path:string;
  i,count:integer;
  PThumbImage1:PThumbImage;
  flag:boolean;
begin
try
  flag:=false;
  case self.workselect of
    wscurrent:begin
      if currentimage.name='' then begin
        MessageDlg('현재 그림/사진이 없습니다.',mterror, [mbOk], 0);
        exit;
      end;
    end;
    wslistselect,wslistall:begin
      count:=0;
      for i:=0 to frmmain.listview1.Items.Count-1 do
        if (workselect=wslistall) or (frmmain.listview1.Items[i].Selected) then begin
          PThumbImage1:=PThumbImage(frmmain.listview1.Items[i].Data);
          if PThumbImage1.imagetype<>itfolder then begin
            inc(count);
            if count=1 then
              path:=sysutils.ExtractFilePath(PThumbImage1.name);
          end;
        end;
      if count=0 then begin
        MessageDlg('생성할 그림/사진이 없습니다.',mterror, [mbOk], 0);
        exit;
      end;
    end;
  end;

  if workselect=wscurrent then begin

    SaveDialog1.Filter:=ComboBox1.Items[ComboBox1.ItemIndex];
    SaveDialog1.FilterIndex:=0;

    if config.c_uselastdir then
      SaveDialog1.InitialDir:=config.lastdir
    else
      SaveDialog1.InitialDir:=ExtractFilePath(currentimage.name);
    s:=sysutils.ChangeFileExt(makefilename(currentimage.name,edit1.Text),
      FIU_GetSelectExt(ComboBox1.ItemIndex+1));
    SaveDialog1.FileName:=ExtractFileName(s);
    SaveDialog1.enablesaveopt:=false;

    if SaveDialog1.Execute=false then exit;

    s:=sysutils.ChangeFileExt(
      SaveDialog1.FileName,
      FIU_GetSelectExt(ComboBox1.ItemIndex+1));
    path:=s;
    config.lastdir:=sysutils.ExtractFilePath(SaveDialog1.FileName);

  end else begin
    if config.c_uselastdir then
      path:=config.lastdir;
    if AdvSelectDirectory(handle,'저장할 폴더선택', '',
      Path, False, False, True)=false then exit;

    if path[length(path)]<>'\' then path:=path+'\';
    config.lastdir:=path;
  end;

  flag:=true;
finally
  if flag=false then btnok.Enabled:=true;
end;

  selectsaveflag:=get_reg_saveopt_flag(FIU_GetFIFType2(FIU_GetSelectExt(ComboBox1.ItemIndex+1)),false);
  config.c_lastselfiletype:=ComboBox1.ItemIndex;

  WorkThread:=TWorkThread.CreateThread;
  WorkThread.workselect:=self.workselect;
  WorkThread.extselectidx:=combobox1.ItemIndex;
  WorkThread.path:=path;
  WorkThread.prefix:=edit1.Text;
  WorkThread.resize:=self.CheckBox1.Checked;
  WorkThread.resize_width:=self.SpinEdit1.Value;
  WorkThread.resize_height:=self.SpinEdit2.Value;
  WorkThread.resize_method:=self.TypeCombo.ItemIndex;
  WorkThread.Onprogress:=WorkThreadOnprogress;
  WorkThread.OnTerminate:=WorkThreadOnTerminate;
  WorkThread.Resume;

end;

procedure Tfrmwork_saveas.WorkThreadOnTerminate(sender:tobject);
begin
  labelcomplete.Visible:=true;
  self.btncancel.Caption:='닫기';
  btncancel.SetFocus;
end;

procedure Tfrmwork_saveas.WorkThreadOnprogress(Sender:TObject;
  totcount,currentcount:integer; msg:string; iserror:boolean);
begin
  ProgressBar1.Max:=totcount;
  ProgressBar1.Position:=currentcount;
  label3.Caption:=format('%d/%d [%s]',[currentcount,totcount,msg]);
  if iserror then
    MessageDlg(msg,mtError, [mbOk], 0);
end;

procedure Tfrmwork_saveas.CancelSeleted;
begin
  if WorkThread=nil then exit;
  WorkThread.Terminate;
  WorkThread.WaitFor;
  WorkThread.Free;
end;

procedure Tfrmwork_saveas.FormDestroy(Sender: TObject);
begin
  config.c_resize_method:=self.TypeCombo.ItemIndex;
end;

procedure Tfrmwork_saveas.Button1Click(Sender: TObject);
begin
  frmsaveopt:=Tfrmsaveopt.Create(self);
  try
    frmsaveopt.selectformat:=Button1.Tag;
    if frmsaveopt.ShowModal=mrok then ;
  finally
    frmsaveopt.Free;
  end;
end;

procedure Tfrmwork_saveas.ComboBox1Change(Sender: TObject);
var
  f:FREE_IMAGE_FORMAT;
begin
  f:=FIU_GetFIFType2(FIU_GetSelectExt(ComboBox1.ItemIndex+1));
  case f of
    FIF_BMP,FIF_JPEG,FIF_PNG,FIF_TIFF:
      Button1.Enabled:=true;
    else
      Button1.Enabled:=false;
  end;
  Button1.Tag:=f;
end;

end.
