📄 uwinhelpfiles.pas
字号:
{
SHG-FileFormat
... Picture Data ...
see other sources
... Makro Data ...
Always1 :Bytes = 1;
NumberOfHotspots :Word;
SizeOfMacroData :DWord;
Hotspots :array[1..NumberOfHotspots] of
record
id0: Byte;
id1: Byte;
id2: Byte;
Left, Top, Width, Height: Word;
HashOrMacroDataOffset: DWord
end;
MacroData :record
case Boolean of
False: (data: array[1..SizeOfMacroData] of Byte;)
True: (macros: array[1..NumberOfMakros] of TMakro)
end;
EditData :array[1..NumberOfHotspots] of
record
HotspotName, TextInformation: StringZ;
end;
StringZ is a 0-terminated string.
EditData seems only to be used in editors for the SHG files, so ignored in
here.
MacroData contains data for any special link, i.e. not id0 in [$E0..$E7], in
that case the HashOrMacroDataOffset is a byte-offset in MacroData to its
entry, in the other case the hash value of the topic to link to.
id0: set of TId0;
TId0 = (id0JumpNotPopUp,
id0JumpNotMakroA,
id0InvisibleHotSpot,
id0LinkToWindowOrFile, //or: HashOrMacroDataOffset is an offset
id0UnknownNotSet5,
id0JumpNotMakroB,
id0UnknownMustBeSet7,
id0UnknownMustBeSet8);
if id0InvisibleHotSpot is set than id1 is also 4 else 0.
TMakro = record
case Boolean of //is a makro?
False: (ExtendedLink: TExtendedLink)
True: (Makro: StringZ;)
end;
TExtendedLink = record
Info: set of (unknown, toWindow, toFile);
TopicHash: DWord;
case toWindow do
window: StringZ;
case toFile do
file: StringZ;
end;
{Creates a Segmented Hyper-Graphic file from a bitmap and a list of hot spots.
~param BMP the bitmap of the SGH file or nil
~param BMPFileName name of the bitmap of the SGH file, if BMP is nil
~param HotSpots the list of hot-spots to add to the bitmap;
the first 15 bytes of each entry are the binary data, the
remnant of the string the destination topic or macro
~param SHGFileName the name for the resulting SGH file }
procedure CreateSegmentedHyperGraphic(BMP: TBitmap; const BMPFileName: String;
HotSpots: TStrings;
const SHGFileName: String);
{Writes a 31 bit value into the stream compressedly. Quite senseless because
about 14 bytes are saved in a file of several kilo bytes, but well, its the
specification.
~param AStream the stream to write the value into
~param Value the value to write }
procedure WriteCompressedDWord(AStream: TStream; Value: DWord);
var WriteWord :Word; //buffer to write a word
begin
if (Value and $7FFF1000) = 0 then //can be compressed?
begin
WriteWord := Value shl 1; //compress value
AStream.WriteBuffer(WriteWord, SizeOf(WriteWord)); //and write it
end
else
begin
WriteWord := (Value shl 1) or 1; //write both words
AStream.WriteBuffer(WriteWord, SizeOf(WriteWord));
WriteWord := (Value shr 15);
AStream.WriteBuffer(WriteWord, SizeOf(WriteWord));
end
end;
{Returns the makro data of links to other Windows Help files and/or windows.
~param Target the target of the link in format "topic[>window][@file.hlp]" }
function CreateMakroText(Target: String): String;
var i :Integer; //index in the target string
NewFile :String; //the new help file for the link
Window :String; //the new windows for the link
begin
i := pos('@', Target); //search the help file
if i <> 0 then //help file specified?
begin //extract it
NewFile := Copy(Target, i + 1, High(Length(Target)));
Delete(Target, i, High(Length(Target)));
end
else
NewFile := '';
i := pos('>', Target); //search the window
if i <> 0 then //window specified?
begin //extract it
Window := Copy(Target, i + 1, High(Length(Target)));
Delete(Target, i, High(Length(Target)));
end
else
Window := '';
//set control byte, use bit 1 and 2 of first byte to select information
Result := Char(Ord(NewFile <> '') shl 2 or Ord(Window <> '') shl 1) +
GetTopicNameHashValue(Target);
if Window <> '' then //add available information
Result := Result + Window + #0;
if NewFile <> '' then
Result := Result + NewFile + #0;
end;
var Bitmap :TBitmap; //the bitmap to write into the shg file
BMPContent :TMemoryStream; //stream for compressed content of bitmap
HSData :TMemoryStream; //stream for data of hot-spots
SHGFile :TFileStream; //stream to write the SHG file
i :Integer; //general counter or index
WriteByte :Byte; //buffer to write the prefix byte
S :String; //buffer to write data
MacroData :String; //data of the hot spots
WriteDWord :DWORD; //buffer to write DWord-values
begin
if Assigned(BMP) then
Bitmap := BMP //use the image
else
Bitmap := TBitmap.Create; //create object to load bitmap
try
if BMP <> Bitmap then //need to load the image from a file
Bitmap.LoadFromFile(BMPFileName); //load the bitmap
{$IFNDEF LINUX}
Bitmap.HandleType := bmDIB; //we need a DIB
{$ENDIF}
if Bitmap.PixelFormat < pf16bit then //we can't read palettes on Unix
//so make sure this is an universal valid pixel format without one
{$IFNDEF LINUX}
Bitmap.PixelFormat := pf16bit;
{$ELSE}
//got some problems with Kylix, changing to 16bit actually set it to custom
Bitmap.PixelFormat := pf32bit;
{$ENDIF}
{$IFNDEF LINUX}
if Bitmap.PixelFormat in [pf24bit, pfCustom] then //bitmaps are written in
Bitmap.PixelFormat := pf32bit; //32 bit, not 24
{$ENDIF}
assert(Bitmap.PixelFormat in [pf16bit, pf32bit]);
BMPContent := TMemoryStream.Create; //create buffer for compressed bitmap
try
GetCompressedBitmapContent(Bitmap, BMPContent); //get content of bitmap
HSData := TMemoryStream.Create; //create buffer for hot-spots
try
MacroData := ''; //no data of macros so far
for i := 0 to HotSpots.Count - 1 do //for each hot-spot
begin
S := HotSpots[i]; //get it
if (S[1] < #$E0) or (S[1] >= #$E8) then //has further information?
begin
HSData.WriteBuffer(S[1], 11); //write binary data
//write index in data instead of hash value
WriteDWord := Length(MacroData);
HSData.WriteBuffer(WriteDWord, SizeOf(WriteDWord));
if S[1] < #$E0 then //a real makro?
//add the text of the macro to the data
MacroData := MacroData + Copy(S, 16, High(Length(S))) + #0
else
//is a link to another window or in another help file
MacroData := MacroData + CreateMakroText(Copy(S, 16,
High(Length(S))));
end
else
HSData.WriteBuffer(S[1], 15); //write its binary data
end;
if MacroData <> '' then //some macros found?
HSData.WriteBuffer(MacroData[1], Length(MacroData)); //write their data
WriteByte := 0; //set byte to end name of hot-spot
for i := 0 to HotSpots.Count - 1 do //for each hot-spot
begin
HSData.WriteBuffer(WriteByte, 1); //end the name (empty name)
S := HotSpots[i]; //get it
Delete(S, 1, 15); //delete binary data
HSData.WriteBuffer(S[1], Length(S) + 1); //write target or macro
end;
//create the SHG file
SHGFile := TFileStream.Create(SHGFileName, fmCreate);
try
S := 'lP'#01#00#08#00#00#00#06 +
//Bit 0 = RunLength; Bit 1 = LZ77
{$IFDEF UseRunLength}
{$IFDEF UseLZ77}
#03
{$ELSE}
#01
{$ENDIF}
{$ELSE}
{$IFDEF UseLZ77}
#02
{$ELSE}
#00
{$ENDIF}
{$ENDIF}
+ #$C0#00#$C0#00#02;
//compression:
SHGFile.WriteBuffer(S[1], Length(S)); //write file header
if Bitmap.PixelFormat = pf16bit then //get bits per pixels
WriteByte := 16 shl 1
else
WriteByte := 32 shl 1;
SHGFile.WriteBuffer(WriteByte, 1);
WriteCompressedDWord(SHGFile, Bitmap.Width); //write size of bitmap
WriteCompressedDWord(SHGFile, Bitmap.Height);
S := #02#00#00#00; //color information
SHGFile.WriteBuffer(S[1], Length(S));
//write size of the compressed bitmap data
WriteCompressedDWord(SHGFile, BMPContent.Position);
//write size of the compressed hot-spot data
WriteCompressedDWord(SHGFile, HSData.Position + 7);
WriteDWord := SHGFile.Position + 12 - 8; //write offset of bitmap
SHGFile.WriteBuffer(WriteDWord, SizeOf(WriteDWord));
inc(WriteDWord, BMPContent.Position); //write offset of hot-spots
SHGFile.WriteBuffer(WriteDWord, SizeOf(WriteDWord));
WriteDWord := 0; //write not used color
SHGFile.WriteBuffer(WriteDWord, SizeOf(WriteDWord));
SHGFile.CopyFrom(BMPContent, 0); //copy the bitmap data
//write header of the list of hot-spots and their number
S := #01 +
Char(HotSpots.Count) + Char(HotSpots.Count shr 8);
SHGFile.WriteBuffer(S[1], Length(S));
WriteDWord := Length(MacroData); //write size of macro data
SHGFile.WriteBuffer(WriteDWord, SizeOf(WriteDWord));
SHGFile.CopyFrom(HSData, 0); //copy the hot-spot data
finally
SHGFile.Free; //close the SHG file
end;
finally
HSData.Free; //free buffer of data of hot-spots
end;
finally
BMPContent.Free; //free buffer of data of the bitmap
end;
finally
if BMP <> Bitmap then //needs to be freed?
Bitmap.Free; //free the bitmap
end;
end;
{Returns the SHG representation of a rectangle as a hot-spot (a link) in a
SHG file.
~param Rect the rectangle to return in SHG format
~result the rectangle in SHG format }
function GetSHGRectString(Rect: TRect): String;
begin
dec(Rect.Right, Rect.Left); //calculate size of the rectangle
dec(Rect.Bottom, Rect.Top);
Result := Char(Rect.Left) + Char(Rect.Left shr 8) + //just the four values
Char(Rect.Top) + Char(Rect.Top shr 8) + //as words
Char(Rect.Right) + Char(Rect.Right shr 8) +
Char(Rect.Bottom) + Char(Rect.Bottom shr 8);
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -