📄 jviconclipboardutils.pas
字号:
{-----------------------------------------------------------------------------
The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/MPL-1.1.html
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
the specific language governing rights and limitations under the License.
The Original Code is: JvClipIcon.PAS, released on 2002-07-04.
The Initial Developers of the Original Code are: Fedor Koshevnikov, Igor Pavluk and Serge Korolev
Copyright (c) 1997, 1998 Fedor Koshevnikov, Igor Pavluk and Serge Korolev
Copyright (c) 2001,2002 SGB Software
All Rights Reserved.
Last Modified: 2002-07-04
You may retrieve the latest version of this file at the Project JEDI's JVCL home page,
located at http://jvcl.sourceforge.net
Known Issues:
-----------------------------------------------------------------------------}
{$I JVCL.INC}
{$I WINDOWSONLY.INC}
unit JvIconClipboardUtils;
interface
uses
{$IFDEF WIN32}
Windows,
{$ELSE}
WinTypes, WinProcs,
{$ENDIF}
SysUtils, Classes, Graphics, Controls;
{ Icon clipboard routines }
var
CF_ICON: Word;
procedure CopyIconToClipboard(Icon: TIcon; BackColor: TColor);
procedure AssignClipboardIcon(Icon: TIcon);
function CreateIconFromClipboard: TIcon;
{ Real-size icons support routines (32-bit only) }
procedure GetIconSize(Icon: HIcon; var W, H: Integer);
function CreateRealSizeIcon(Icon: TIcon): HIcon;
procedure DrawRealSizeIcon(Canvas: TCanvas; Icon: TIcon; X, Y: Integer);
implementation
uses
Consts, Clipbrd,
JvVCLUtils;
{ Icon clipboard routines }
{$IFDEF WIN32}
function CreateBitmapFromIcon(Icon: TIcon; BackColor: TColor): TBitmap;
var
Ico: HIcon;
W, H: Integer;
begin
Ico := CreateRealSizeIcon(Icon);
try
GetIconSize(Ico, W, H);
Result := TBitmap.Create;
try
Result.Width := W; Result.Height := H;
with Result.Canvas do
begin
Brush.Color := BackColor;
FillRect(Rect(0, 0, W, H));
DrawIconEx(Handle, 0, 0, Ico, W, H, 0, 0, DI_NORMAL);
end;
except
Result.Free;
raise;
end;
finally
DestroyIcon(Ico);
end;
end;
{$ELSE}
function CreateBitmapFromIcon(Icon: TIcon; BackColor: TColor): TBitmap;
begin
Result := JvVCLUtils.CreateBitmapFromIcon(Icon, BackColor);
end;
{$ENDIF}
procedure CopyIconToClipboard(Icon: TIcon; BackColor: TColor);
var
Bmp: TBitmap;
Stream: TStream;
Data: THandle;
Format: Word;
Palette: HPalette;
Buffer: Pointer;
begin
Bmp := CreateBitmapFromIcon(Icon, BackColor);
try
Stream := TMemoryStream.Create;
try
Icon.SaveToStream(Stream);
Palette := 0;
with Clipboard do
begin
Open;
try
Clear;
Bmp.SaveToClipboardFormat(Format, Data, Palette);
SetClipboardData(Format, Data);
if Palette <> 0 then
SetClipboardData(CF_PALETTE, Palette);
Data := GlobalAlloc(HeapAllocFlags, Stream.Size);
try
if Data <> 0 then
begin
Buffer := GlobalLock(Data);
try
Stream.Seek(0, 0);
Stream.Read(Buffer^, Stream.Size);
SetClipboardData(CF_ICON, Data);
finally
GlobalUnlock(Data);
end;
end;
except
GlobalFree(Data);
raise;
end;
finally
Close;
end;
end;
finally
Stream.Free;
end;
finally
Bmp.Free;
end;
end;
procedure AssignClipboardIcon(Icon: TIcon);
var
Stream: TStream;
Data: THandle;
Buffer: Pointer;
begin
if not Clipboard.HasFormat(CF_ICON) then
Exit;
with Clipboard do
begin
Open;
try
Data := GetClipboardData(CF_ICON);
Buffer := GlobalLock(Data);
try
Stream := TMemoryStream.Create;
try
Stream.Write(Buffer^, GlobalSize(Data));
Stream.Seek(0, 0);
Icon.LoadFromStream(Stream);
finally
Stream.Free;
end;
finally
GlobalUnlock(Data);
end;
finally
Close;
end;
end;
end;
function CreateIconFromClipboard: TIcon;
begin
Result := nil;
if not Clipboard.HasFormat(CF_ICON) then
Exit;
Result := TIcon.Create;
try
AssignClipboardIcon(Result);
except
Result.Free;
raise;
end;
end;
{ Real-size icons support routines }
const
rc3_StockIcon = 0;
rc3_Icon = 1;
rc3_Cursor = 2;
type
PCursorOrIcon = ^TCursorOrIcon;
TCursorOrIcon = packed record
Reserved: Word;
wType: Word;
Count: Word;
end;
PIconRec = ^TIconRec;
TIconRec = packed record
Width: Byte;
Height: Byte;
Colors: Word;
Reserved1: Word;
Reserved2: Word;
DIBSize: Longint;
DIBOffset: Longint;
end;
procedure OutOfResources; near;
begin
raise EOutOfResources.Create(ResStr(SOutOfResources));
end;
{$IFDEF WIN32}
function WidthBytes(I: Longint): Longint;
begin
Result := ((I + 31) div 32) * 4;
end;
function GetDInColors(BitCount: Word): Integer;
begin
case BitCount of
1, 4, 8:
Result := 1 shl BitCount;
else
Result := 0;
end;
end;
function DupBits(Src: HBITMAP; Size: TPoint; Mono: Boolean): HBITMAP;
var
DC, Mem1, Mem2: HDC;
Old1, Old2: HBITMAP;
Bitmap: Windows.TBitmap;
begin
Mem1 := CreateCompatibleDC(0);
Mem2 := CreateCompatibleDC(0);
GetObject(Src, SizeOf(Bitmap), @Bitmap);
if Mono then
Result := CreateBitmap(Size.X, Size.Y, 1, 1, nil)
else
begin
DC := GetDC(0);
if DC = 0 then
OutOfResources;
try
Result := CreateCompatibleBitmap(DC, Size.X, Size.Y);
if Result = 0 then
OutOfResources;
finally
ReleaseDC(0, DC);
end;
end;
if Result <> 0 then
begin
Old1 := SelectObject(Mem1, Src);
Old2 := SelectObject(Mem2, Result);
StretchBlt(Mem2, 0, 0, Size.X, Size.Y, Mem1, 0, 0, Bitmap.bmWidth,
Bitmap.bmHeight, SrcCopy);
if Old1 <> 0 then
SelectObject(Mem1, Old1);
if Old2 <> 0 then
SelectObject(Mem2, Old2);
end;
DeleteDC(Mem1);
DeleteDC(Mem2);
end;
procedure TwoBitsFromDIB(var BI: TBitmapInfoHeader; var XorBits, AndBits: HBITMAP);
type
PLongArray = ^TLongArray;
TLongArray = array [0..1] of Longint;
var
Temp: HBITMAP;
NumColors: Integer;
DC: HDC;
Bits: Pointer;
Colors: PLongArray;
IconSize: TPoint;
BM: Windows.TBitmap;
begin
IconSize.X := GetSystemMetrics(SM_CXICON);
IconSize.Y := GetSystemMetrics(SM_CYICON);
with BI do
begin
biHeight := biHeight shr 1; { Size in record is doubled }
biSizeImage := WidthBytes(Longint(biWidth) * biBitCount) * biHeight;
NumColors := GetDInColors(biBitCount);
end;
DC := GetDC(0);
if DC = 0 then
OutOfResources;
try
Bits := Pointer(Longint(@BI) + SizeOf(BI) + NumColors * SizeOf(TRGBQuad));
Temp := CreateDIBitmap(DC, BI, CBM_INIT, Bits, PBitmapInfo(@BI)^, DIB_RGB_COLORS);
if Temp = 0 then
OutOfResources;
try
GetObject(Temp, SizeOf(BM), @BM);
IconSize.X := BM.bmWidth;
IconSize.Y := BM.bmHeight;
XorBits := DupBits(Temp, IconSize, False);
finally
DeleteObject(Temp);
end;
with BI do
begin
Inc(Longint(Bits), biSizeImage);
biBitCount := 1;
biSizeImage := WidthBytes(Longint(biWidth) * biBitCount) * biHeight;
biClrUsed := 2;
biClrImportant := 2;
end;
Colors := Pointer(Longint(@BI) + SizeOf(BI));
Colors^[0] := 0;
Colors^[1] := $FFFFFF;
Temp := CreateDIBitmap(DC, BI, CBM_INIT, Bits, PBitmapInfo(@BI)^, DIB_RGB_COLORS);
if Temp = 0 then
OutOfResources;
try
AndBits := DupBits(Temp, IconSize, True);
finally
DeleteObject(Temp);
end;
finally
ReleaseDC(0, DC);
end;
end;
procedure ReadIcon(Stream: TStream; var Icon: HICON; ImageCount: Integer;
StartOffset: Integer);
type
PIconRecArray = ^TIconRecArray;
TIconRecArray = array [0..300] of TIconRec;
var
List: PIconRecArray;
HeaderLen, Length: Integer;
Colors, BitsPerPixel: Word;
C1, C2, N, Index: Integer;
IconSize: TPoint;
DC: HDC;
BI: PBitmapInfoHeader;
ResData: Pointer;
XorBits, AndBits: HBITMAP;
XorInfo, AndInfo: Windows.TBitmap;
XorMem, AndMem: Pointer;
XorLen, AndLen: Integer;
begin
HeaderLen := SizeOf(TIconRec) * ImageCount;
List := AllocMem(HeaderLen);
try
Stream.Read(List^, HeaderLen);
IconSize.X := GetSystemMetrics(SM_CXICON);
IconSize.Y := GetSystemMetrics(SM_CYICON);
DC := GetDC(0);
if DC = 0 then
OutOfResources;
try
BitsPerPixel := GetDeviceCaps(DC, PLANES) * GetDeviceCaps(DC, BITSPIXEL);
if BitsPerPixel = 24 then
Colors := 0
else
Colors := 1 shl BitsPerPixel;
finally
ReleaseDC(0, DC);
end;
Index := -1;
{ the following code determines which image most closely matches the
current device. It is not meant to absolutely match Windows
(known broken) algorithm }
C2 := 0;
for N := 0 to ImageCount - 1 do
begin
C1 := List^[N].Colors;
if C1 = Colors then
begin
Index := N;
Break;
end
else
if Index = -1 then
begin
if C1 <= Colors then
begin
Index := N;
C2 := List^[N].Colors;
end;
end
else
if C1 > C2 then
Index := N;
end;
if Index = -1 then
Index := 0;
with List^[Index] do
begin
BI := AllocMem(DIBSize);
try
Stream.Seek(DIBOffset - (HeaderLen + StartOffset), 1);
Stream.Read(BI^, DIBSize);
TwoBitsFromDIB(BI^, XorBits, AndBits);
GetObject(AndBits, SizeOf(Windows.TBitmap), @AndInfo);
GetObject(XorBits, SizeOf(Windows.TBitmap), @XorInfo);
IconSize.X := AndInfo.bmWidth;
IconSize.Y := AndInfo.bmHeight;
with AndInfo do
AndLen := bmWidthBytes * bmHeight * bmPlanes;
with XorInfo do
XorLen := bmWidthBytes * bmHeight * bmPlanes;
Length := AndLen + XorLen;
ResData := AllocMem(Length);
try
AndMem := ResData;
with AndInfo do
XorMem := Pointer(Longint(ResData) + AndLen);
GetBitmapBits(AndBits, AndLen, AndMem);
GetBitmapBits(XorBits, XorLen, XorMem);
DeleteObject(XorBits);
DeleteObject(AndBits);
Icon := CreateIcon(HInstance, IconSize.X, IconSize.Y,
XorInfo.bmPlanes, XorInfo.bmBitsPixel, AndMem, XorMem);
if Icon = 0 then
OutOfResources;
finally
FreeMem(ResData, Length);
end;
finally
FreeMem(BI, DIBSize);
end;
end;
finally
FreeMem(List, HeaderLen);
end;
end;
procedure GetIconSize(Icon: HIcon; var W, H: Integer);
var
IconInfo: TIconInfo;
BM: Windows.TBitmap;
begin
if GetIconInfo(Icon, IconInfo) then
begin
try
if IconInfo.hbmColor <> 0 then
begin
GetObject(IconInfo.hbmColor, SizeOf(BM), @BM);
W := BM.bmWidth;
H := BM.bmHeight;
end
else
if IconInfo.hbmMask <> 0 then
begin { Monochrome icon }
GetObject(IconInfo.hbmMask, SizeOf(BM), @BM);
W := BM.bmWidth;
H := BM.bmHeight shr 1; { Size in record is doubled }
end
else
begin
W := GetSystemMetrics(SM_CXICON);
H := GetSystemMetrics(SM_CYICON);
end;
finally
if IconInfo.hbmColor <> 0 then
DeleteObject(IconInfo.hbmColor);
if IconInfo.hbmMask <> 0 then
DeleteObject(IconInfo.hbmMask);
end;
end
else
begin
W := GetSystemMetrics(SM_CXICON);
H := GetSystemMetrics(SM_CYICON);
end;
end;
{$ELSE}
procedure GetIconSize(Icon: HICON; var W, H: Integer);
begin
W := GetSystemMetrics(SM_CXICON);
H := GetSystemMetrics(SM_CYICON);
end;
{$ENDIF WIN32}
{$IFDEF WIN32}
function CreateRealSizeIcon(Icon: TIcon): HIcon;
var
Mem: TMemoryStream;
CI: TCursorOrIcon;
begin
Result := 0;
Mem := TMemoryStream.Create;
try
Icon.SaveToStream(Mem);
Mem.Position := 0;
Mem.ReadBuffer(CI, SizeOf(CI));
case CI.wType of
RC3_STOCKICON: Result := LoadIcon(0, IDI_APPLICATION);
RC3_ICON: ReadIcon(Mem, Result, CI.Count, SizeOf(CI));
else Result := CopyIcon(Icon.Handle);
end;
finally
Mem.Free;
end;
end;
{$ELSE}
function CreateRealSizeIcon(Icon: TIcon): HIcon;
begin
Result := CopyIcon(hInstance, Icon.Handle);
end;
{$ENDIF}
{$IFDEF WIN32}
procedure DrawRealSizeIcon(Canvas: TCanvas; Icon: TIcon; X, Y: Integer);
var
Ico: HIcon;
W, H: Integer;
begin
Ico := CreateRealSizeIcon(Icon);
try
GetIconSize(Ico, W, H);
DrawIconEx(Canvas.Handle, X, Y, Ico, W, H, 0, 0, DI_NORMAL);
finally
DestroyIcon(Ico);
end;
end;
{$ELSE}
begin
Canvas.Draw(X, Y, Icon);
end;
{$ENDIF}
initialization
{ The following string should not be localized }
CF_ICON := RegisterClipboardFormat('Delphi Icon');
TPicture.RegisterClipboardFormat(CF_ICON, TIcon);
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -