Added ability to extract all TIMs to PNG; Now PNG's name includes CLUT index.

This commit is contained in:
meffi@lab313.ru
2014-04-10 23:22:23 +00:00
parent 1d63ac1b95
commit 90c0e78a66
9 changed files with 278 additions and 169 deletions

View File

@@ -6,7 +6,7 @@
<MainSource>tim2view.dpr</MainSource>
<Base>True</Base>
<Config Condition="'$(Config)'==''">Release</Config>
<Platform Condition="'$(Platform)'==''">Win64</Platform>
<Platform Condition="'$(Platform)'==''">Win32</Platform>
<TargetedPlatforms>3</TargetedPlatforms>
<AppType>Application</AppType>
</PropertyGroup>

Binary file not shown.

View File

@@ -78,12 +78,15 @@ begin
Exit;
pFile := GetMemory(cSectorHeaderSize);
tmp := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
tmp.Read(pFile^[0], cSectorHeaderSize);
Result := ((Sz mod cSectorSize) = 0) and
(CompareMem(@cSectorHeader, pFile, cSectorHeaderSize));
tmp.free;
FreeMemory(pFile);
try
tmp := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
tmp.Read(pFile^[0], cSectorHeaderSize);
Result := ((Sz mod cSectorSize) = 0) and (CompareMem(@cSectorHeader, pFile, cSectorHeaderSize));
finally
tmp.free;
FreeMemory(pFile);
end;
end;
procedure ReplaceTimInFileFromMemory(const FileName: string; TIM: PTIM;

View File

@@ -7,16 +7,19 @@ uses
const
cProgramName = 'Tim2View by [Lab 313]';
cProgramVersion = '2.0 Stable';
cProgramVersion = '2.0 Release';
cExtractedTimsDir = 'TIMS';
cExtractedPngsDir = 'PNGS';
cMaxFileSize = $2EAEED80;
cAutoExtractionTimFormat = '%s_%.6d_%.2db' + '.tim';
cAutoExtractionPngFormat = '%s_%.6d_%.2db_%.2dc' + '.png';
cCLUTGridColsCount = 32;
sStatusBarScanningFile = 'Scanning File...';
sStatusBarTimsExtracting = 'TIMs Extracting...';
sStatusBarTimsExtracted = 'Exctracted Successfully!';
sStatusBarPngsExtracting = 'PNGs Extracting...';
sStatusBarExtracted = 'Exctracted Successfully!';
sStatusBarParsingResult = 'Parsing Result...';
sScanResultGood = 'Scan completed!';
sSelectDirCaption = 'Please, select directory for scan...';

View File

@@ -576,9 +576,9 @@ object frmMain: TfrmMain
TabOrder = 0
object lvList: TListView
Left = 0
Top = 0
Top = 49
Width = 240
Height = 481
Height = 432
Align = alClient
Columns = <
item
@@ -613,6 +613,39 @@ object frmMain: TfrmMain
ViewStyle = vsReport
OnChange = lvListChange
OnData = lvListData
ExplicitLeft = 1
ExplicitTop = 28
ExplicitHeight = 448
end
object pnlExtractAll: TPanel
Left = 0
Top = 0
Width = 240
Height = 49
Align = alTop
BevelOuter = bvLowered
TabOrder = 1
object btnExtractAllTims: TButton
Left = 139
Top = 1
Width = 100
Height = 47
Action = actExtractPNGs
Align = alRight
TabOrder = 0
WordWrap = True
ExplicitLeft = 128
end
object btnExtractPNGs: TButton
Left = 1
Top = 1
Width = 100
Height = 47
Action = actExtractTIMs
Align = alLeft
TabOrder = 1
WordWrap = True
end
end
end
object pnlImage: TPanel
@@ -923,11 +956,17 @@ object frmMain: TfrmMain
Caption = '&Open TIMs with T2V'
OnExecute = actAssocTimsExecute
end
object actExtractList: TAction
Caption = '&Extract TIMs'
object actExtractTIMs: TAction
Caption = 'Extract all &TIMs'#13#10'(Shift+F2)'
Enabled = False
ShortCut = 112
OnExecute = actExtractListExecute
ShortCut = 8305
OnExecute = actExtractTIMsExecute
end
object actExtractPNGs: TAction
Caption = '&Extract all PNGs'#13#10'(Shift+F4)'
Enabled = False
ShortCut = 8307
OnExecute = actExtractPNGsExecute
end
object actChangeClutIdx: TAction
end
@@ -941,12 +980,6 @@ object frmMain: TfrmMain
object pmList: TPopupMenu
Left = 640
Top = 502
object ExtractTIMs1: TMenuItem
Action = actExtractList
end
object N6: TMenuItem
Caption = '-'
end
object ExtractTIM1: TMenuItem
Action = actExtractTim
end

View File

@@ -77,14 +77,16 @@ type
mnTimInfoMain: TMenuItem;
actAssocTims: TAction;
mnAssociate: TMenuItem;
N6: TMenuItem;
actExtractList: TAction;
ExtractTIMs1: TMenuItem;
actExtractTIMs: TAction;
pbTim: TImage;
btnShowClut: TButton;
cbbCLUT: TComboBox;
actReturnFocus: TAction;
actDrawSelectedTim: TAction;
actExtractPNGs: TAction;
pnlExtractAll: TPanel;
btnExtractAllTims: TButton;
btnExtractPNGs: TButton;
procedure btnStopScanClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure lvListData(Sender: TObject; Item: TListItem);
@@ -107,13 +109,14 @@ type
procedure actStretchExecute(Sender: TObject);
procedure actTimInfoExecute(Sender: TObject);
procedure actAssocTimsExecute(Sender: TObject);
procedure actExtractListExecute(Sender: TObject);
procedure actExtractTIMsExecute(Sender: TObject);
procedure cbbTranspModeChange(Sender: TObject);
procedure btnShowClutClick(Sender: TObject);
procedure lvListChange(Sender: TObject; Item: TListItem;
Change: TItemChange);
procedure actReturnFocusExecute(Sender: TObject);
procedure actDrawSelectedTimExecute(Sender: TObject);
procedure actExtractPNGsExecute(Sender: TObject);
private
{ Private declarations }
// pResult: PNativeXml;
@@ -134,7 +137,8 @@ type
function ListIdx: Integer;
function TimIdx(Index: Integer): TScanTim;
function SelTim(NewBitMode: Integer = $FF): PTIM;
function SelTimName: string;
function FormatTimName(const FileName: string; ListIdx_, BitMode: Integer): string;
function FormatPngName(const FileName: string; ListIdx_, BitMode, Clut: Integer): string;
procedure DrawSelTim;
procedure DrawSelClut;
procedure UpdateCLUTInfo;
@@ -158,7 +162,7 @@ var
implementation
uses
uCDIMAGE, uBrowseForFolder, System.Win.Registry;
uCDIMAGE, uBrowseForFolder, System.Win.Registry, Vcl.Imaging.pngimage;
{$R *.dfm}
@@ -319,10 +323,10 @@ begin
Close;
end;
procedure TfrmMain.actExtractListExecute(Sender: TObject);
procedure TfrmMain.actExtractTIMsExecute(Sender: TObject);
var
I, OFFSET, BIT_MODE, SIZE: Integer;
FName, TIM_NAME, Path: string;
FName, Path: string;
IsImage: Boolean;
ScanTim: TScanTim;
TIM: PTIM;
@@ -332,6 +336,8 @@ begin
FName := ScanRes.ScanFile;
IsImage := ScanRes.IsImage;
pbProgress.Position := 0;
pbProgress.Max := ScanRes.Count;
for I := 1 to ScanRes.Count do
begin
ScanTim := TimIdx(I - 1);
@@ -339,26 +345,79 @@ begin
SIZE := ScanTim.Size;
BIT_MODE := ScanTim.BitMode;
TIM_NAME := Format(cAutoExtractionTimFormat, [ExtractJustName(FName), I, BIT_MODE]);
Path := IncludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0)) + cExtractedTimsDir);
CreateDir(Path);
Path := IncludeTrailingPathDelimiter(Path + ExtractFileName(FName));
CreateDir(Path);
TIM := LoadTimFromFile(FName, OFFSET, IsImage, SIZE);
SaveTimToFile(Path + TIM_NAME, TIM);
SaveTimToFile(Path + FormatTimName(FName, I - 1, BIT_MODE), TIM);
FreeTIM(TIM);
pbProgress.Position := I;
Application.ProcessMessages;
end;
lblStatus.Caption := sStatusBarTimsExtracted;
lblStatus.Caption := sStatusBarExtracted;
MessageBeep(MB_ICONINFORMATION);
pbProgress.Position := 0;
end;
procedure TfrmMain.actExtractPNGsExecute(Sender: TObject);
var
I, OFFSET, BIT_MODE, SIZE: Integer;
FName, Path: string;
IsImage: Boolean;
ScanTim: TScanTim;
TIM: PTIM;
PNG_: PPNGImage;
begin
lblStatus.Caption := sStatusBarPngsExtracting;
FName := ScanRes.ScanFile;
IsImage := ScanRes.IsImage;
New(PNG_);
pbProgress.Position := 0;
pbProgress.Max := ScanRes.Count;
for I := 1 to ScanRes.Count do
begin
ScanTim := TimIdx(I - 1);
OFFSET := ScanTim.Position;
SIZE := ScanTim.Size;
BIT_MODE := ScanTim.BitMode;
Path := IncludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0)) + cExtractedPngsDir);
CreateDir(Path);
Path := IncludeTrailingPathDelimiter(Path + ExtractFileName(FName));
CreateDir(Path);
PNG_^ := TPngImage.CreateBlank(COLOR_RGBALPHA, 16, ScanTim.Width, ScanTim.Height);
PNG_^.CompressionLevel := 0;
PNG_^.Filters := [];
TIM := LoadTimFromFile(FName, OFFSET, IsImage, SIZE);
TimToPNG(TIM, cbbCLUT.ItemIndex, PNG_, cbbTranspMode.ItemIndex);
PNG_^.SaveToFile(Path + FormatPngName(FName, I - 1, BIT_MODE, 0));
PNG_^.Free;
FreeTIM(TIM);
pbProgress.Position := I;
Application.ProcessMessages;
end;
Dispose(PNG_);
lblStatus.Caption := sStatusBarExtracted;
MessageBeep(MB_ICONINFORMATION);
pbProgress.Position := 0;
end;
procedure TfrmMain.actExtractTimExecute(Sender: TObject);
var
TIM: PTIM;
begin
dlgSaveTIM.FileName := SelTimName;
dlgSaveTIM.FileName := FormatTimName(ScanRes.ScanFile, ListIdx, TimIdx(ListIdx).BitMode);
if not dlgSaveTIM.Execute then Exit;
@@ -423,12 +482,8 @@ begin
end;
procedure TfrmMain.actTim2PngExecute(Sender: TObject);
var
FName: string;
begin
FName := SelTimName;
FName := ChangeFileExt(FName, '.png');
dlgSavePNG.FileName := FName;
dlgSavePNG.FileName := FormatPngName(ScanRes.ScanFile, ListIdx, TimIdx(ListIdx).BitMode, cbbCLUT.ItemIndex);
if not dlgSavePNG.Execute then Exit;
@@ -459,8 +514,8 @@ begin
+ Tab + '%s' + Row + Row +
'HEADER INFO' + Row + 'Version:' + Tab + '%d' + Row + 'BPP:' + Tab + '%d'
+ Row + Row, [SelTimName, Index + 1, TimIdx(Index).Position,
BppToBitMode(TIM), IsGoodTIM,
+ Row + Row, [FormatTimName(ScanRes.ScanFile, Index, TimIdx(Index).BitMode),
Index + 1, TimIdx(Index).Position, BppToBitMode(TIM), IsGoodTIM,
GetTimVersion(TIM), GetTimBPP(TIM)]);
@@ -558,7 +613,8 @@ begin
cbbFiles.Enabled := (cbbFiles.Items.Count <> 0);
lvList.Enabled := cbbFiles.Enabled;
actExtractList.Enabled := cbbFiles.Enabled;
actExtractTIMs.Enabled := cbbFiles.Enabled;
actExtractPNGs.Enabled := cbbFiles.Enabled;
actCloseFile.Enabled := cbbFiles.Enabled;
actCloseFiles.Enabled := cbbFiles.Enabled;
actReplaceTim.Enabled := (lvList.SelCount = 1);
@@ -587,9 +643,14 @@ begin
Result^.HEAD^.bBPP := NewBitMode;
end;
function TfrmMain.SelTimName: string;
function TfrmMain.FormatTimName(const FileName: string; ListIdx_, BitMode: Integer): string;
begin
Result := Format(cAutoExtractionTimFormat, [ExtractJustName(ScanRes.ScanFile), ListIdx + 1, TimIdx(ListIdx).BitMode]);
Result := Format(cAutoExtractionTimFormat, [ExtractJustName(FileName), ListIdx_ + 1, BitMode]);
end;
function TfrmMain.FormatPngName(const FileName: string; ListIdx_, BitMode, Clut: Integer): string;
begin
Result := Format(cAutoExtractionPngFormat, [ExtractJustName(FileName), ListIdx_ + 1, BitMode, Clut + 1]);
end;
procedure TfrmMain.DrawSelClut;
@@ -647,10 +708,10 @@ begin
PNG^ := nil;
end;
if cbbCLUT.Text = sThisTimHasNoClut then
(*if cbbCLUT.Text = sThisTimHasNoClut then
Index := -1
else
Index := cbbCLUT.ItemIndex;
*)Index := cbbCLUT.ItemIndex;
TimToPNG(TIM, Index, PNG, cbbTranspMode.ItemIndex);
PNG.AssignTo(pbTim.Picture.Bitmap);

View File

@@ -89,87 +89,91 @@ var
begin
Synchronize(StartScan);
pSrcFileStream := TFileStream.Create(pScanResult.ScanFile, fmOpenRead or
fmShareDenyWrite);
pSrcFileStream.Position := 0;
try
if pScanResult.IsImage then
pSectorBufferSize := cSectorBufferSize
else
pSectorBufferSize := cClearBufferSize;
if pScanResult.IsImage then
pSectorBufferSize := cSectorBufferSize
else
pSectorBufferSize := cClearBufferSize;
pClearBufferSize := cClearBufferSize;
pClearBufferSize := cClearBufferSize;
SectorBuffer := GetMemory(pSectorBufferSize);
ClearBuffer := GetMemory(pClearBufferSize);
SectorBuffer := GetMemory(pSectorBufferSize);
ClearBuffer := GetMemory(pClearBufferSize);
pSrcFileStream := TFileStream.Create(pScanResult.ScanFile, fmOpenRead or
fmShareDenyWrite);
TIM := CreateTIM;
pSrcFileStream.Position := 0;
pStatusText := sStatusBarScanningFile;
Synchronize(SetStatusText);
TIM := CreateTIM;
pRealBufSize := pSrcFileStream.Read(SectorBuffer^[0], pSectorBufferSize);
Inc(pFilePos, pRealBufSize);
ClearSectorBuffer(SectorBuffer, ClearBuffer);
pStatusText := sStatusBarScanningFile;
Synchronize(SetStatusText);
pScanFinished := False;
pTIMNumber := 0;
pRealBufSize := pSrcFileStream.Read(SectorBuffer^[0], pSectorBufferSize);
Inc(pFilePos, pRealBufSize);
ClearSectorBuffer(SectorBuffer, ClearBuffer);
while not pStopScan do
begin
if LoadTimFromBuf(ClearBuffer, TIM, pClearBufferPosition) then
pScanFinished := False;
pTIMNumber := 0;
while not pStopScan do
begin
if pScanResult.IsImage then
pTimPosition := pFilePos - pRealBufSize +
((pClearBufferPosition - 1) div cSectorDataSize) * cSectorSize +
((pClearBufferPosition - 1) mod cSectorDataSize) + cSectorInfoSize
else
pTimPosition := pFilePos - pRealBufSize + (pClearBufferPosition - 1);
if pTimPosition >= pFileSize then Break;
TIM^.dwTimPosition := pTimPosition;
Inc(pTIMNumber);
TIM^.dwTimNumber := pTIMNumber;
AddResult(TIM);
end;
if pClearBufferPosition = (pClearBufferSize div 2) then
begin
if pScanFinished then Break;
pScanFinished := (pFilePos = pFileSize);
pClearBufferPosition := 0;
Move(SectorBuffer^[pSectorBufferSize div 2], SectorBuffer^[0], pSectorBufferSize div 2);
if pScanFinished then
if LoadTimFromBuf(ClearBuffer, TIM, pClearBufferPosition) then
begin
if pRealBufSize >= (pSectorBufferSize div 2) then
// Need to check file size
pRealBufSize := pRealBufSize - (pSectorBufferSize div 2);
end
else
begin
pRealBufSize := pSrcFileStream.Read(SectorBuffer^[pSectorBufferSize div 2], pSectorBufferSize div 2);
Inc(pFilePos, pRealBufSize);
pRealBufSize := pRealBufSize + (pSectorBufferSize div 2);
if pScanResult.IsImage then
pTimPosition := pFilePos - pRealBufSize +
((pClearBufferPosition - 1) div cSectorDataSize) * cSectorSize +
((pClearBufferPosition - 1) mod cSectorDataSize) + cSectorInfoSize
else
pTimPosition := pFilePos - pRealBufSize + (pClearBufferPosition - 1);
if pTimPosition >= pFileSize then Break;
TIM^.dwTimPosition := pTimPosition;
Inc(pTIMNumber);
TIM^.dwTimNumber := pTIMNumber;
AddResult(TIM);
end;
Synchronize(UpdateProgressBar);
if pClearBufferPosition = (pClearBufferSize div 2) then
begin
if pScanFinished then Break;
ClearSectorBuffer(SectorBuffer, ClearBuffer);
pScanFinished := (pFilePos = pFileSize);
pClearBufferPosition := 0;
Move(SectorBuffer^[pSectorBufferSize div 2], SectorBuffer^[0], pSectorBufferSize div 2);
if pScanFinished then
begin
if pRealBufSize >= (pSectorBufferSize div 2) then
// Need to check file size
pRealBufSize := pRealBufSize - (pSectorBufferSize div 2);
end
else
begin
pRealBufSize := pSrcFileStream.Read(SectorBuffer^[pSectorBufferSize div 2], pSectorBufferSize div 2);
Inc(pFilePos, pRealBufSize);
pRealBufSize := pRealBufSize + (pSectorBufferSize div 2);
end;
Synchronize(UpdateProgressBar);
ClearSectorBuffer(SectorBuffer, ClearBuffer);
end;
end;
finally
FreeTIM(TIM);
FreeMemory(SectorBuffer);
FreeMemory(ClearBuffer);
pSrcFileStream.Free;
pStopScan := True;
pFilePos := 0;
pStatusText := '';
Synchronize(FinishScan);
end;
FreeTIM(TIM);
FreeMemory(SectorBuffer);
FreeMemory(ClearBuffer);
pSrcFileStream.Free;
pStopScan := True;
pFilePos := 0;
pStatusText := '';
Synchronize(FinishScan);
end;
procedure TScanThread.FinishScan;
@@ -201,7 +205,8 @@ procedure TScanThread.StartScan;
begin
frmMain.cbbFiles.Enabled := False;
frmMain.lvList.Enabled := False;
frmMain.actExtractList.Enabled := False;
frmMain.actExtractTIMs.Enabled := False;
frmMain.actExtractPNGs.Enabled := False;
frmMain.pbProgress.Max := GetFileSizeAPI(pScanResult.ScanFile);
frmMain.pbProgress.Position := 0;

View File

@@ -35,19 +35,19 @@ unit uSettings;
{ TSettings }
procedure TCustomSettings.LoadFromFile() ;
var
Stream: TStream;
begin
if not FileExists(FFileName) then Exit;
procedure TCustomSettings.LoadFromFile() ;
var
Stream: TStream;
begin
if not FileExists(FFileName) then Exit;
Stream := TFileStream.Create(FFileName, fmOpenRead or fmShareDenyWrite) ;
try
LoadFromStream(Stream) ;
finally
Stream.Free;
end;
end;
try
Stream := TFileStream.Create(FFileName, fmOpenRead or fmShareDenyWrite) ;
LoadFromStream(Stream) ;
finally
Stream.Free;
end;
end;
procedure TCustomSettings.LoadFromStream(const Stream: TStream) ;
var

View File

@@ -372,56 +372,58 @@ var
Sector: TCDSector;
P, TIM_FULL_SECTORS: Integer;
begin
sImageStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
try
sImageStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
TimSectorNumber := Position div cSectorSize + 1;
TimOffsetInSector := Position mod cSectorSize - cSectorInfoSize;
TimStartSectorPos := (TimSectorNumber - 1) * cSectorSize;
FirstPartSize := cSectorDataSize - TimOffsetInSector;
TimSectorNumber := Position div cSectorSize + 1;
TimOffsetInSector := Position mod cSectorSize - cSectorInfoSize;
TimStartSectorPos := (TimSectorNumber - 1) * cSectorSize;
FirstPartSize := cSectorDataSize - TimOffsetInSector;
New(TIM_BUF);
P := 0;
New(TIM_BUF);
P := 0;
if SIZE < FirstPartSize then
FirstPartSize := SIZE;
if SIZE < FirstPartSize then
FirstPartSize := SIZE;
sImageStream.Seek(TimStartSectorPos, soBeginning);
sImageStream.Read(Sector, cSectorSize);
Move(Sector.dwData[TimOffsetInSector], TIM_BUF^[P], FirstPartSize);
Inc(P, FirstPartSize);
Inc(TimStartSectorPos, cSectorSize);
sImageStream.Seek(TimStartSectorPos, soBeginning);
TIM_FULL_SECTORS := (SIZE - P) div cSectorDataSize;
while TIM_FULL_SECTORS > 0 do
begin
sImageStream.Seek(TimStartSectorPos, soBeginning);
sImageStream.Read(Sector, cSectorSize);
Move(Sector.dwData[0], TIM_BUF^[P], cSectorDataSize);
Inc(P, cSectorDataSize);
Move(Sector.dwData[TimOffsetInSector], TIM_BUF^[P], FirstPartSize);
Inc(P, FirstPartSize);
Inc(TimStartSectorPos, cSectorSize);
sImageStream.Seek(TimStartSectorPos, soBeginning);
Dec(TIM_FULL_SECTORS);
TIM_FULL_SECTORS := (SIZE - P) div cSectorDataSize;
while TIM_FULL_SECTORS > 0 do
begin
sImageStream.Read(Sector, cSectorSize);
Move(Sector.dwData[0], TIM_BUF^[P], cSectorDataSize);
Inc(P, cSectorDataSize);
Inc(TimStartSectorPos, cSectorSize);
sImageStream.Seek(TimStartSectorPos, soBeginning);
Dec(TIM_FULL_SECTORS);
end;
sImageStream.Read(Sector, cSectorSize);
if SIZE > P then
begin
LastPartSize := SIZE - P;
Move(Sector.dwData[0], TIM_BUF^[P], LastPartSize);
end;
finally
P := 0;
Result := nil;
LoadTimFromBuf(TIM_BUF, Result, P);
sImageStream.Free;
Dispose(TIM_BUF);
end;
sImageStream.Read(Sector, cSectorSize);
if SIZE > P then
begin
LastPartSize := SIZE - P;
Move(Sector.dwData[0], TIM_BUF^[P], LastPartSize);
end;
P := 0;
Result := nil;
LoadTimFromBuf(TIM_BUF, Result, P);
sImageStream.Free;
Dispose(TIM_BUF);
end;
function LoadTimFromStream(Stream: TStream; var Position: Integer;
@@ -455,9 +457,12 @@ var
begin
if not ImageScan then
begin
sTIM := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
Result := LoadTimFromStream(sTIM, Position, dwSize);
sTIM.Free;
try
sTIM := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
Result := LoadTimFromStream(sTIM, Position, dwSize);
finally
sTIM.Free;
end;
Exit;
end;
@@ -468,8 +473,7 @@ procedure SaveTimToFile(const FileName: string; TIM: PTIM);
var
tmp: TMemoryStream;
begin
if TIM = nil then
Exit;
if TIM = nil then Exit;
tmp := TMemoryStream.Create;
tmp.Write(TIM^.DATA^[0], TIM^.dwSize);