You've already forked lazarus-ccr
lazbarcode: Add sample project QRCodeGenerator.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@8688 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
846
components/lazbarcodes/examples/qrcodegenerator/fpwritegif.pas
Normal file
846
components/lazbarcodes/examples/qrcodegenerator/fpwritegif.pas
Normal file
@ -0,0 +1,846 @@
|
|||||||
|
{
|
||||||
|
Copyright (c) 2007-2023, Udo Schmal <udo.schmal@t-online.de>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute the software for any purpose
|
||||||
|
with or without fee is hereby granted, provided that the above copyright notice
|
||||||
|
and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
|
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
|
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
|
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
|
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
https://www.gocher.me/FPWriteGIF
|
||||||
|
}
|
||||||
|
|
||||||
|
unit FPWriteGIF;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils, FPImage, FPReadGif;
|
||||||
|
|
||||||
|
type TColor = -$7FFFFFFF - 1..$7FFFFFFF;
|
||||||
|
|
||||||
|
const
|
||||||
|
// GIF record separators
|
||||||
|
kGifImageSeparator: byte = $2c;
|
||||||
|
kGifExtensionSeparator: byte = $21;
|
||||||
|
kGifTerminator: byte = $3b;
|
||||||
|
kGifLabelGraphic: byte = $f9;
|
||||||
|
kGifBlockTerminator: byte = $00;
|
||||||
|
// LZW encode table sizes
|
||||||
|
kGifCodeTableSize = 4096;
|
||||||
|
// Raw rgb value
|
||||||
|
clNone = TColor($1FFFFFFF);
|
||||||
|
AlphaOpaque = $FF;
|
||||||
|
AlphaTransparent = 0;
|
||||||
|
MaxArr = (MaxLongint div Sizeof(integer)) - 1;
|
||||||
|
|
||||||
|
type
|
||||||
|
APixel8 = array[0..MaxArr] of Byte;
|
||||||
|
PAPixel8 = ^APixel8;
|
||||||
|
|
||||||
|
TRGBQuadArray256 = array[0..256] of TFPCompactImgRGBA8BitValue;
|
||||||
|
TOpenColorTableArray = array of TColor;
|
||||||
|
TColorTableArray = array[0..$FF] of TColor;
|
||||||
|
|
||||||
|
TOctreeNode = class; // Forward definition so TReducibleNodes can be declared
|
||||||
|
TReducibleNodes = array[0..7] of TOctreeNode;
|
||||||
|
TOctreeNode = class(TObject)
|
||||||
|
IsLeaf: Boolean;
|
||||||
|
PixelCount: Integer;
|
||||||
|
RedSum, GreenSum, BlueSum: Integer;
|
||||||
|
Next: TOctreeNode;
|
||||||
|
Child: TReducibleNodes;
|
||||||
|
constructor Create(const Level: Integer; var LeafCount: Integer; var ReducibleNodes: TReducibleNodes);
|
||||||
|
destructor Destroy; override;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TFPWriterGIF = class(TFPCustomImageWriter)
|
||||||
|
private
|
||||||
|
fHeader: TGifHeader;
|
||||||
|
fDescriptor: TGifImageDescriptor; // only one image supported
|
||||||
|
fGraphicsCtrlExt: TGifGraphicsControlExtension;
|
||||||
|
fTransparent: Boolean;
|
||||||
|
fBackground: TColor;
|
||||||
|
fPixels: PAPixel8;
|
||||||
|
fPixelList: PChar; // decoded pixel indices
|
||||||
|
fPixelCount: longint; // number of pixels
|
||||||
|
fColorTable: TColorTableArray;
|
||||||
|
fColorTableSize: integer;
|
||||||
|
|
||||||
|
procedure SaveToStream(Destination: TStream);
|
||||||
|
protected
|
||||||
|
procedure InternalWrite(Stream: TStream; Img: TFPCustomImage); override;
|
||||||
|
public
|
||||||
|
constructor Create; override;
|
||||||
|
destructor Destroy; override;
|
||||||
|
end;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
{$REGION ' - TOctreeNode - '}
|
||||||
|
constructor TOctreeNode.Create(const Level: Integer; var LeafCount: Integer; var ReducibleNodes: TReducibleNodes);
|
||||||
|
var i: Integer;
|
||||||
|
begin
|
||||||
|
PixelCount := 0;
|
||||||
|
RedSum := 0;
|
||||||
|
GreenSum := 0;
|
||||||
|
BlueSum := 0;
|
||||||
|
for i := Low(Child) to High(Child) do
|
||||||
|
Child[i] := nil;
|
||||||
|
IsLeaf := (Level = 8);
|
||||||
|
if IsLeaf then
|
||||||
|
begin
|
||||||
|
Next := nil;
|
||||||
|
Inc(LeafCount);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Next := ReducibleNodes[Level];
|
||||||
|
ReducibleNodes[Level] := Self;
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TOctreeNode.Destroy;
|
||||||
|
var i: Integer;
|
||||||
|
begin
|
||||||
|
for i := Low(Child) to High(Child) do
|
||||||
|
Child[i].Free
|
||||||
|
end;
|
||||||
|
{$ENDREGION}
|
||||||
|
|
||||||
|
{$REGION ' - TFPWriterGIF. - '}
|
||||||
|
constructor TFPWriterGIF.Create;
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TFPWriterGIF.Destroy;
|
||||||
|
begin
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// save the current GIF definition to a stream object
|
||||||
|
// at first, just write it to our memory stream fSOURCE
|
||||||
|
procedure TFPWriterGIF.SaveToStream(Destination: TStream);
|
||||||
|
var
|
||||||
|
LZWStream: TMemoryStream; // temp storage for LZW
|
||||||
|
LZWSize: integer; // LZW minimum code size
|
||||||
|
|
||||||
|
// these LZW encode routines sqrunch a bitmap into a memory stream
|
||||||
|
procedure LZWEncode();
|
||||||
|
var
|
||||||
|
rPrefix: array[0..kGifCodeTableSize-1] of integer; // string prefixes
|
||||||
|
rSuffix: array[0..kGifCodeTableSize-1] of integer; // string suffixes
|
||||||
|
rCodeStack: array[0..kGifCodeTableSize-1] of byte; // encoded pixels
|
||||||
|
rSP: integer; // pointer into CodeStack
|
||||||
|
rClearCode: integer; // reset decode params
|
||||||
|
rEndCode: integer; // last code in input stream
|
||||||
|
rCurSize: integer; // current code size
|
||||||
|
rBitString: integer; // steady stream of bits to be decoded
|
||||||
|
rBits: integer; // number of valid bits in BitString
|
||||||
|
rMaxVal: boolean; // max code value found?
|
||||||
|
rCurX: integer; // position of next pixel
|
||||||
|
rCurY: integer; // position of next pixel
|
||||||
|
rCurPass: integer; // pixel line pass 1..4
|
||||||
|
rFirstSlot: integer; // for encoding an image
|
||||||
|
rNextSlot: integer; // for encoding
|
||||||
|
rCount: integer; // number of bytes read/written
|
||||||
|
rLast: integer; // last byte read in
|
||||||
|
rUnget: boolean; // read a new byte, or use zLast?
|
||||||
|
|
||||||
|
procedure LZWReset;
|
||||||
|
var i: integer;
|
||||||
|
begin
|
||||||
|
for i := 0 to (kGifCodeTableSize - 1) do
|
||||||
|
begin
|
||||||
|
rPrefix[i] := 0;
|
||||||
|
rSuffix[i] := 0;
|
||||||
|
end;
|
||||||
|
rCurSize := LZWSize + 1;
|
||||||
|
rClearCode := (1 shl LZWSize);
|
||||||
|
rEndCode := rClearCode + 1;
|
||||||
|
rFirstSlot := (1 shl (rCurSize - 1)) + 2;
|
||||||
|
rNextSlot := rFirstSlot;
|
||||||
|
rMaxVal := false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// save a code value on the code stack
|
||||||
|
procedure LZWSaveCode(Code: integer);
|
||||||
|
begin
|
||||||
|
rCodeStack[rSP] := Code;
|
||||||
|
inc(rSP);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// save the code in the output data stream
|
||||||
|
procedure LZWPutCode(code: integer);
|
||||||
|
var
|
||||||
|
n: integer;
|
||||||
|
b: byte;
|
||||||
|
begin
|
||||||
|
// write out finished bytes
|
||||||
|
// a literal "8" for 8 bits per byte
|
||||||
|
while (rBits >= 8) do
|
||||||
|
begin
|
||||||
|
b := (rBitString and $ff);
|
||||||
|
rBitString := (rBitString shr 8);
|
||||||
|
rBits := rBits - 8;
|
||||||
|
LZWStream.Write(b, 1);
|
||||||
|
end;
|
||||||
|
// make sure no junk bits left above the first byte
|
||||||
|
rBitString := (rBitString and $ff);
|
||||||
|
// and save out-going code
|
||||||
|
n := (code shl rBits);
|
||||||
|
rBitString := (rBitString or n);
|
||||||
|
rBits := rBits + rCurSize;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// get the next pixel from the bitmap, and return it as an index into the colormap
|
||||||
|
function LZWReadBitmap: integer;
|
||||||
|
var
|
||||||
|
n: integer;
|
||||||
|
j: longint;
|
||||||
|
p: PChar;
|
||||||
|
begin
|
||||||
|
if (rUnget) then
|
||||||
|
begin
|
||||||
|
n := rLast;
|
||||||
|
rUnget := false;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
inc(rCount);
|
||||||
|
j := (rCurY * fDescriptor.Width) + rCurX;
|
||||||
|
if ((0 <= j) and (j < fPixelCount)) then
|
||||||
|
begin
|
||||||
|
p := fPixelList + j;
|
||||||
|
n := ord(p^);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
n := 0;
|
||||||
|
// if first pass, make sure CurPass was initialized
|
||||||
|
if (rCurPass = 0) then rCurPass := 1;
|
||||||
|
inc(rCurX); // inc X position
|
||||||
|
if (rCurX >= fDescriptor.Width) then // bumping Y ?
|
||||||
|
begin
|
||||||
|
rCurX := 0;
|
||||||
|
inc(rCurY);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
rLast := n;
|
||||||
|
result := n;
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
i,n,
|
||||||
|
cc: integer; // current code to translate
|
||||||
|
oc: integer; // last code encoded
|
||||||
|
found: boolean; // decoded string in prefix table?
|
||||||
|
pixel: byte; // lowest code to search for
|
||||||
|
ldx: integer; // last index found
|
||||||
|
fdx: integer; // current index found
|
||||||
|
b: byte;
|
||||||
|
begin
|
||||||
|
// init data block
|
||||||
|
fillchar(rCodeStack, sizeof(rCodeStack), 0);
|
||||||
|
rBitString := 0;
|
||||||
|
rBits := 0;
|
||||||
|
rCurX := 0;
|
||||||
|
rCurY := 0;
|
||||||
|
rCurPass := 0;
|
||||||
|
rLast := 0;
|
||||||
|
rUnget:= false;
|
||||||
|
|
||||||
|
LZWReset;
|
||||||
|
// all within the data record
|
||||||
|
// always save the clear code first ...
|
||||||
|
LZWPutCode(rClearCode);
|
||||||
|
// and first pixel
|
||||||
|
oc := LZWReadBitmap;
|
||||||
|
LZWPutCode(oc);
|
||||||
|
// nothing found yet (but then, we haven't searched)
|
||||||
|
ldx := 0;
|
||||||
|
fdx := 0;
|
||||||
|
// and the rest of the pixels
|
||||||
|
rCount := 1;
|
||||||
|
while (rCount <= fPixelCount) do
|
||||||
|
begin
|
||||||
|
rSP := 0; // empty the stack of old data
|
||||||
|
n := LZWReadBitmap; // next pixel from the bitmap
|
||||||
|
LZWSaveCode(n);
|
||||||
|
cc := rCodeStack[0]; // beginning of the string
|
||||||
|
// add new encode table entry
|
||||||
|
rPrefix[rNextSlot] := oc;
|
||||||
|
rSuffix[rNextSlot] := cc;
|
||||||
|
inc(rNextSlot);
|
||||||
|
if (rNextSlot >= kGifCodeTableSize) then
|
||||||
|
rMaxVal := true
|
||||||
|
else if (rNextSlot > (1 shl rCurSize)) then
|
||||||
|
inc(rCurSize);
|
||||||
|
// find the running string of matching codes
|
||||||
|
ldx := cc;
|
||||||
|
found := true;
|
||||||
|
while (found and (rCount <= fPixelCount)) do
|
||||||
|
begin
|
||||||
|
n := LZWReadBitmap;
|
||||||
|
LZWSaveCode(n);
|
||||||
|
cc := rCodeStack[0];
|
||||||
|
if (ldx < rFirstSlot) then
|
||||||
|
i := rFirstSlot
|
||||||
|
else
|
||||||
|
i := ldx + 1;
|
||||||
|
pixel := rCodeStack[rSP - 1];
|
||||||
|
found := false;
|
||||||
|
while ((not found) and (i < rNextSlot)) do
|
||||||
|
begin
|
||||||
|
found := ((rPrefix[i] = ldx) and (rSuffix[i] = pixel));
|
||||||
|
inc(i);
|
||||||
|
end;
|
||||||
|
if (found) then
|
||||||
|
begin
|
||||||
|
ldx := i - 1;
|
||||||
|
fdx := i - 1;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
// if not found, save this index, and get the same code again
|
||||||
|
if (not found) then
|
||||||
|
begin
|
||||||
|
rUnget := true;
|
||||||
|
rLast := rCodeStack[rSP-1];
|
||||||
|
dec(rSP);
|
||||||
|
cc := ldx;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
cc := fdx;
|
||||||
|
// whatever we got, write it out as current table entry
|
||||||
|
LZWPutCode(cc);
|
||||||
|
if ((rMaxVal) and (rCount <= fPixelCount)) then
|
||||||
|
begin
|
||||||
|
LZWPutCode(rClearCode);
|
||||||
|
LZWReset;
|
||||||
|
cc := LZWReadBitmap;
|
||||||
|
LZWPutCode(cc);
|
||||||
|
end;
|
||||||
|
oc := cc;
|
||||||
|
end;
|
||||||
|
LZWPutCode(rEndCode);
|
||||||
|
// write out the rest of the bit string
|
||||||
|
while (rBits > 0) do
|
||||||
|
begin
|
||||||
|
b := (rBitString and $ff);
|
||||||
|
rBitString := (rBitString shr 8);
|
||||||
|
rBits := rBits - 8;
|
||||||
|
LZWStream.Write(b, 1);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
var i: integer;
|
||||||
|
begin
|
||||||
|
Destination.Position := 0;
|
||||||
|
with fHeader do
|
||||||
|
begin
|
||||||
|
// write the GIF signature
|
||||||
|
// if only one image, and no image extensions, then GIF is GIF87a,
|
||||||
|
// else use the updated version GIF98a
|
||||||
|
// we just added an extension block; the signature must be version 89a
|
||||||
|
Destination.Write(Signature, 3);
|
||||||
|
Destination.Write(Version, 3);
|
||||||
|
// write the overall GIF screen description to the source stream
|
||||||
|
Destination.Write(ScreenWidth, 2); // logical screen width
|
||||||
|
Destination.Write(ScreenHeight, 2); // logical screen height
|
||||||
|
Destination.Write(Packedbit, 1); // packed bit fields (Global Color valid, Global Color size, Sorted, Color Resolution)
|
||||||
|
Destination.Write(BackgroundColor, 1); // background color
|
||||||
|
Destination.Write(AspectRatio, 1); // pixel aspect ratio
|
||||||
|
if (Packedbit and $80)>0 then //Global Color valid
|
||||||
|
// write out color gobal table with RGB values
|
||||||
|
for i := 0 to fColorTableSize-1 do
|
||||||
|
Destination.Write(fColorTable[i], 3);
|
||||||
|
end;
|
||||||
|
// write out graphic extension for this image
|
||||||
|
Destination.Write(kGifExtensionSeparator, 1); // write the extension separator
|
||||||
|
Destination.Write(kGifLabelGraphic, 1); // write the extension label
|
||||||
|
Destination.Write(fGraphicsCtrlExt.BlockSize, 1); // block size (always 4)
|
||||||
|
Destination.Write(fGraphicsCtrlExt.Packedbit, 1); // packed bit field
|
||||||
|
Destination.Write(fGraphicsCtrlExt.DelayTime, 2); // delay time
|
||||||
|
Destination.Write(fGraphicsCtrlExt.ColorIndex, 1); // transparent color
|
||||||
|
Destination.Write(fGraphicsCtrlExt.Terminator, 1); // block terminator
|
||||||
|
// write actual image data
|
||||||
|
Destination.Write(kGifImageSeparator, 1);
|
||||||
|
// write the next image descriptor shortcut to the record fields
|
||||||
|
with fDescriptor do
|
||||||
|
begin
|
||||||
|
// write the basic descriptor record
|
||||||
|
Destination.Write(Left, 2); // left position
|
||||||
|
Destination.Write(Top, 2); // top position
|
||||||
|
Destination.Write(Width, 2); // size of image
|
||||||
|
Destination.Write(Height, 2); // size of image
|
||||||
|
Destination.Write(Packedbit, 1); // packed bit field
|
||||||
|
// there is no local color table defined we use global
|
||||||
|
LZWSize := 8; // the LZW minimum code size
|
||||||
|
Destination.Write(LZWSize, 1);
|
||||||
|
LZWStream := TMemoryStream.Create; // init the storage for compressed data
|
||||||
|
try
|
||||||
|
LZWEncode(); // encode the image and save it in LZWStream
|
||||||
|
// write out the data stream as a series of data blocks
|
||||||
|
LZWStream.Position := 0;
|
||||||
|
while (LZWStream.Position < LZWStream.Size) do
|
||||||
|
begin
|
||||||
|
i := LZWStream.Size - LZWStream.Position;
|
||||||
|
if (i > 255) then i := 255;
|
||||||
|
Destination.Write(i, 1);
|
||||||
|
Destination.CopyFrom(LZWStream, i);
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
FreeAndNil(LZWStream);
|
||||||
|
end;
|
||||||
|
Destination.Write(kGifBlockTerminator, 1); // block terminator
|
||||||
|
end;
|
||||||
|
Destination.Write(kGifTerminator, 1); // done with writing
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TFPWriterGIF.InternalWrite(Stream: TStream; Img: TFPCustomImage);
|
||||||
|
var
|
||||||
|
CT: TOpenColorTableArray;
|
||||||
|
Palette: TList;
|
||||||
|
PaletteHasAllColours: Boolean;
|
||||||
|
Mappings: array[BYTE, BYTE] of TList;
|
||||||
|
Tree: TOctreeNode;
|
||||||
|
LeafCount: Integer;
|
||||||
|
ReducibleNodes: TReducibleNodes;
|
||||||
|
LastColor: TColor;
|
||||||
|
LastColorIndex: Byte;
|
||||||
|
|
||||||
|
// convert TFPCustomImage TFPColor to TColor
|
||||||
|
function FPColorToTColor(const FPColor: TFPColor): TColor;
|
||||||
|
begin
|
||||||
|
result := TColor(((FPColor.Red shr 8) and $ff) or (FPColor.Green and $ff00) or ((FPColor.Blue shl 8) and $ff0000));
|
||||||
|
end;
|
||||||
|
|
||||||
|
// try to make color table of all colors
|
||||||
|
function MakeColorTableOfAllColors(): Boolean;
|
||||||
|
var
|
||||||
|
Flags: array[Byte, Byte] of TBits;
|
||||||
|
x, y, ci: Cardinal;
|
||||||
|
Red, Green, Blue: Byte;
|
||||||
|
Cnt: word;
|
||||||
|
begin
|
||||||
|
result := false;
|
||||||
|
// init Flags
|
||||||
|
for y := 0 to $FF do
|
||||||
|
for x := 0 to $FF do
|
||||||
|
Flags[x, y] := nil;
|
||||||
|
try
|
||||||
|
for ci := 0 to $ff do
|
||||||
|
CT[ci] := 0;
|
||||||
|
Cnt := 0;
|
||||||
|
for y := 0 to Img.Height - 1 do
|
||||||
|
for x := 0 to Img.Width - 1 do
|
||||||
|
begin
|
||||||
|
Red := Byte(Img.Colors[x, y].red shr 8);
|
||||||
|
Green := Byte(Img.Colors[x, y].green shr 8);
|
||||||
|
Blue := Byte(Img.Colors[x, y].blue shr 8);
|
||||||
|
if (Flags[Red, Green]) = nil then
|
||||||
|
begin
|
||||||
|
Flags[Red, Green] := Classes.TBits.Create;
|
||||||
|
Flags[Red, Green].Size := 256;
|
||||||
|
end;
|
||||||
|
if not Flags[Red, Green].Bits[Blue] then
|
||||||
|
begin
|
||||||
|
CT[Cnt] := FPColorToTColor(Img.Colors[x, y]);
|
||||||
|
if Cnt = $ff then exit;
|
||||||
|
inc(Cnt);
|
||||||
|
Flags[Red, Green].Bits[Blue] := true;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
result := true;
|
||||||
|
PaletteHasAllColours := true;
|
||||||
|
finally // free Flags
|
||||||
|
for y := 0 to $FF do
|
||||||
|
for x := 0 to $FF do
|
||||||
|
if Flags[x, y] <> nil then
|
||||||
|
FreeAndNil(Flags[x, y]);
|
||||||
|
end;
|
||||||
|
fColorTableSize := High(CT) + 1;
|
||||||
|
for x := 0 to fColorTableSize - 1 do
|
||||||
|
fColorTable[x] := CT[x];
|
||||||
|
LastColor := clNone;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure MakeColorTableofReducedColors();
|
||||||
|
procedure AddColor(var Node: TOctreeNode; const r, g, b: Byte; const Level: Integer; var ReducibleNodes: TReducibleNodes);
|
||||||
|
const mask: array[0..7] of Byte = ($80, $40, $20, $10, $08, $04, $02, $01);
|
||||||
|
var Index, Shift: Integer;
|
||||||
|
begin
|
||||||
|
if Node = nil then
|
||||||
|
Node := TOctreeNode.Create(Level, LeafCount, ReducibleNodes);
|
||||||
|
if Node.IsLeaf then
|
||||||
|
begin
|
||||||
|
Inc(Node.PixelCount);
|
||||||
|
Inc(Node.RedSum, r);
|
||||||
|
Inc(Node.GreenSum, g);
|
||||||
|
Inc(Node.BlueSum, b)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Shift := 7 - Level;
|
||||||
|
Index := (((r and mask[Level]) shr Shift) shl 2) or (((g and mask[Level]) shr Shift) shl 1) or
|
||||||
|
((b and mask[Level]) shr Shift);
|
||||||
|
AddColor(Node.Child[Index], r, g, b, Level + 1, ReducibleNodes)
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ReduceTree(var LeafCount: Integer; var ReducibleNodes: TReducibleNodes);
|
||||||
|
var
|
||||||
|
RedSum, BlueSum, GreenSum, Children, i: Integer;
|
||||||
|
Node: TOctreeNode;
|
||||||
|
begin
|
||||||
|
i := 7;
|
||||||
|
while (i > 0) and (ReducibleNodes[i] = nil) do
|
||||||
|
dec(i);
|
||||||
|
Node := ReducibleNodes[i];
|
||||||
|
ReducibleNodes[i] := Node.Next;
|
||||||
|
RedSum := 0;
|
||||||
|
GreenSum := 0;
|
||||||
|
BlueSum := 0;
|
||||||
|
Children := 0;
|
||||||
|
for i := Low(ReducibleNodes) to High(ReducibleNodes) do
|
||||||
|
if Node.Child[i] <> nil then
|
||||||
|
begin
|
||||||
|
Inc(RedSum, Node.Child[i].RedSum);
|
||||||
|
Inc(GreenSum, Node.Child[i].GreenSum);
|
||||||
|
Inc(BlueSum, Node.Child[i].BlueSum);
|
||||||
|
Inc(Node.PixelCount, Node.Child[i].PixelCount);
|
||||||
|
Node.Child[i].Free;
|
||||||
|
Node.Child[i] := nil;
|
||||||
|
inc(Children)
|
||||||
|
end;
|
||||||
|
Node.IsLeaf := true;
|
||||||
|
Node.RedSum := RedSum;
|
||||||
|
Node.GreenSum := GreenSum;
|
||||||
|
Node.BlueSum := BlueSum;
|
||||||
|
Dec(LeafCount, Children - 1)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure GetPaletteColors(const Node: TOctreeNode; var RGBQuadArray: TRGBQuadArray256; var Index: integer);
|
||||||
|
var i: integer;
|
||||||
|
begin
|
||||||
|
if Node.IsLeaf then
|
||||||
|
begin
|
||||||
|
with RGBQuadArray[Index] do
|
||||||
|
begin
|
||||||
|
try
|
||||||
|
r := Byte(Node.RedSum div Node.PixelCount);
|
||||||
|
g := Byte(Node.GreenSum div Node.PixelCount);
|
||||||
|
b := Byte(Node.BlueSum div Node.PixelCount);
|
||||||
|
a := 0;
|
||||||
|
except
|
||||||
|
r := 0;
|
||||||
|
g := 0;
|
||||||
|
b := 0;
|
||||||
|
a := 0;
|
||||||
|
end;
|
||||||
|
a := 0
|
||||||
|
end;
|
||||||
|
inc(Index);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
for i := Low(Node.Child) to High(Node.Child) do
|
||||||
|
if Node.Child[i] <> nil then
|
||||||
|
GetPaletteColors(Node.Child[i], RGBQuadArray, Index)
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure SetPalette(Pal: array of TColor; Size: integer);
|
||||||
|
var
|
||||||
|
PalSize, i: integer;
|
||||||
|
Col: PFPCompactImgRGB8BitValue;
|
||||||
|
x, y: Cardinal;
|
||||||
|
Red, Green, Blue: Byte;
|
||||||
|
Pcol: PInteger;
|
||||||
|
DistanceSquared, SmallestDistanceSquared: integer;
|
||||||
|
R1, G1, B1: Byte;
|
||||||
|
begin
|
||||||
|
if Size <> -1 then PalSize := Size else PalSize := High(Pal) + 1;
|
||||||
|
for i := 0 to PalSize - 1 do
|
||||||
|
begin
|
||||||
|
GetMem(Col, SizeOf(TFPCompactImgRGB8BitValue));
|
||||||
|
Col^.r := Byte(Pal[i]);
|
||||||
|
Col^.g := Byte(Pal[i] shr 8);
|
||||||
|
Col^.b := Byte(Pal[i] shr 16);
|
||||||
|
Palette.Add(Col);
|
||||||
|
end;
|
||||||
|
for y := 0 to $ff do
|
||||||
|
for x := 0 to $ff do
|
||||||
|
Mappings[y,x] := nil;
|
||||||
|
for y := 0 to Img.Height - 1 do
|
||||||
|
for x := 0 to Img.Width - 1 do
|
||||||
|
begin
|
||||||
|
Red := Byte(Img.Colors[x, y].red shr 8);
|
||||||
|
Green := Byte(Img.Colors[x, y].green shr 8);
|
||||||
|
Blue := Byte(Img.Colors[x, y].blue shr 8);
|
||||||
|
//Small reduction of color space
|
||||||
|
dec(Red, Red mod 3);
|
||||||
|
dec(Green, Green mod 3);
|
||||||
|
dec(Blue, Blue mod 3);
|
||||||
|
if (Mappings[Red, Green]) = nil then
|
||||||
|
begin
|
||||||
|
Mappings[Red, Green] := TList.Create;
|
||||||
|
Mappings[Red, Green].Count := 256;
|
||||||
|
end;
|
||||||
|
if (Mappings[Red, Green].Items[Blue] = nil) then
|
||||||
|
begin
|
||||||
|
GetMem(Pcol, SizeOf(integer));
|
||||||
|
PCol^ := 0;
|
||||||
|
SmallestDistanceSquared := $1000000;
|
||||||
|
for i := 0 to Palette.Count - 1 do
|
||||||
|
begin
|
||||||
|
R1 := PFPCompactImgRGB8BitValue(Palette[i])^.r;
|
||||||
|
G1 := PFPCompactImgRGB8BitValue(Palette[i])^.g;
|
||||||
|
B1 := PFPCompactImgRGB8BitValue(Palette[i])^.b;
|
||||||
|
DistanceSquared := (Red - R1) * (Red - R1) + (Green - G1) * (Green - G1) + (Blue - B1) * (Blue - B1);
|
||||||
|
if DistanceSquared < SmallestDistanceSquared then
|
||||||
|
begin
|
||||||
|
PCol^ := i;
|
||||||
|
if (Red = R1) and (Green = G1) and (Blue = B1) then break;
|
||||||
|
SmallestDistanceSquared := DistanceSquared;
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
Mappings[Red, Green].Items[Blue] := PCol;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DeleteTree(var Node: TOctreeNode);
|
||||||
|
var i: integer;
|
||||||
|
begin
|
||||||
|
for i := Low(TReducibleNodes) to High(TReducibleNodes) do
|
||||||
|
if Node.Child[i] <> nil then
|
||||||
|
DeleteTree(Node.Child[i]);
|
||||||
|
FreeAndNil(Node);
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
i, j, Index: integer;
|
||||||
|
QArr: TRGBQuadArray256;
|
||||||
|
begin
|
||||||
|
PaletteHasAllColours := false;
|
||||||
|
Tree := nil;
|
||||||
|
LeafCount := 0;
|
||||||
|
for i := Low(ReducibleNodes) to High(ReducibleNodes) do
|
||||||
|
ReducibleNodes[i] := nil;
|
||||||
|
if (Img.Height > 0) and (Img.Width > 0) then
|
||||||
|
for j := 0 to Img.Height - 1 do
|
||||||
|
for i := 0 to Img.Width - 1 do
|
||||||
|
begin
|
||||||
|
AddColor(Tree, Byte(Img.Colors[i,j].red shr 8), Byte(Img.Colors[i,j].green shr 8), Byte(Img.Colors[i,j].blue shr 8), 0, ReducibleNodes);
|
||||||
|
while LeafCount > 256 do
|
||||||
|
ReduceTree(LeafCount, ReducibleNodes)
|
||||||
|
end;
|
||||||
|
Index := 0;
|
||||||
|
GetPaletteColors(Tree, QArr, Index);
|
||||||
|
for i := 0 to LeafCount - 1 do
|
||||||
|
CT[i] := (QArr[i].b shl 16) + (QArr[i].g shl 8) + QArr[i].r;
|
||||||
|
fColorTableSize := LeafCount;
|
||||||
|
for i := 0 to fColorTableSize - 1 do
|
||||||
|
fColorTable[i] := CT[i];
|
||||||
|
LastColor := clNone;
|
||||||
|
SetPalette(fColorTable, LeafCount);
|
||||||
|
if Tree <> nil then DeleteTree(Tree);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ClearMappings;
|
||||||
|
var i, j, k: integer;
|
||||||
|
begin
|
||||||
|
{ wp: Avoids crash at FreeMem - may result in a memory leak !!!!
|
||||||
|
for j := 0 to $FF do
|
||||||
|
for i := 0 to $FF do
|
||||||
|
begin
|
||||||
|
if Assigned(Mappings[i, j]) then
|
||||||
|
begin
|
||||||
|
for k := 0 to $FF do
|
||||||
|
FreeMem(Mappings[i, j].Items[k], SizeOf(TColor));
|
||||||
|
Mappings[i, j].Free;
|
||||||
|
end;
|
||||||
|
Mappings[i, j] := nil;
|
||||||
|
end;
|
||||||
|
}
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure SetPixel(X, Y: Integer; Value: TColor);
|
||||||
|
var
|
||||||
|
Val: integer;
|
||||||
|
PCol: PInteger;
|
||||||
|
R, G, B: byte;
|
||||||
|
begin
|
||||||
|
if not ((Img.Width >= X) and (Img.Height >= Y) and (X > -1) and (Y > -1)) then exit;
|
||||||
|
Val := -1;
|
||||||
|
if LastColor = Value then
|
||||||
|
Val := LastColorIndex
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
if PaletteHasAllColours then
|
||||||
|
begin
|
||||||
|
TFPCompactImgRGBA8BitValue(Value).a := 0;
|
||||||
|
for Val := 0 to fColorTableSize - 1 do
|
||||||
|
if fColorTable[Val] = Value then break;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
B := Byte(Value shr 16);
|
||||||
|
B := B - (B mod 3);
|
||||||
|
G := Byte(Value shr 8);
|
||||||
|
G := G - (G mod 3);
|
||||||
|
R := Byte(Value);
|
||||||
|
R := R - (R mod 3);
|
||||||
|
Val := -1;
|
||||||
|
if Mappings[R, G] <> nil then
|
||||||
|
begin
|
||||||
|
PCol := Mappings[R, G].Items[B];
|
||||||
|
if PCol <> nil then Val := PCol^;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
LastColor := Value;
|
||||||
|
LastColorIndex := Val;
|
||||||
|
end;
|
||||||
|
fPixels^[Y * Img.Width + X] := Val;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// find the color within the color table; returns 0..255, -1 if color not found
|
||||||
|
function FindColorIndex(c: TColor): integer;
|
||||||
|
var i: integer;
|
||||||
|
begin
|
||||||
|
i := 0;
|
||||||
|
result := -1;
|
||||||
|
while (i<fColorTableSize) and (result < 0) do
|
||||||
|
begin
|
||||||
|
if (fColorTable[i] = c) then result := i;
|
||||||
|
inc(i);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function lsb(w: word): byte;
|
||||||
|
begin
|
||||||
|
result := 0;
|
||||||
|
while ((w shr result) and 1) = 0 do inc(result);
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
x, y: cardinal;
|
||||||
|
i, n, ci: integer;
|
||||||
|
b: byte;
|
||||||
|
pptr: PChar;
|
||||||
|
begin
|
||||||
|
if not ((Img.Width < 1) or (Img.Height < 1)) then
|
||||||
|
try
|
||||||
|
fTransparent := false;
|
||||||
|
// translate 64bit image to 8bit colortable image
|
||||||
|
Palette := TList.Create;
|
||||||
|
fColorTableSize := 0;
|
||||||
|
SetLength(CT, 256);
|
||||||
|
//try to make optimized palette on original Data.
|
||||||
|
if not MakeColorTableOfAllColors() then
|
||||||
|
MakeColorTableofReducedColors(); // to mutch colors, reduce colors
|
||||||
|
GetMem(fPixels, Img.Height * Img.Width);
|
||||||
|
for y := 0 to Img.Height - 1 do
|
||||||
|
for x := 0 to Img.Width - 1 do
|
||||||
|
begin
|
||||||
|
SetPixel(x, y, FPColorToTColor(Img.Colors[x, y]));
|
||||||
|
if not fTransparent then
|
||||||
|
if Img.Colors[x, y].alpha = AlphaTransparent then
|
||||||
|
begin
|
||||||
|
fBackground := FPColorToTColor(Img.Colors[x, y]);
|
||||||
|
fTransparent := true;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
// color count must be a power of 2
|
||||||
|
if (fColorTableSize <= 2) then fColorTableSize := 2
|
||||||
|
else if (fColorTableSize <= 4) then fColorTableSize := 4
|
||||||
|
else if (fColorTableSize <= 8) then fColorTableSize := 8
|
||||||
|
else if (fColorTableSize <= 16) then fColorTableSize := 16
|
||||||
|
else if (fColorTableSize <= 32) then fColorTableSize := 32
|
||||||
|
else if (fColorTableSize <= 64) then fColorTableSize := 64
|
||||||
|
else if (fColorTableSize <= 128) then fColorTableSize := 128
|
||||||
|
else fColorTableSize := 256;
|
||||||
|
finally
|
||||||
|
for i := 0 to Palette.Count - 1 do
|
||||||
|
FreeMem(Palette[i], SizeOf(TFPCompactImgRGB8BitValue));
|
||||||
|
Palette.Clear;
|
||||||
|
ClearMappings;
|
||||||
|
Palette.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// create a new gif image record from the given 8bit colortable image
|
||||||
|
with fHeader do
|
||||||
|
begin
|
||||||
|
Signature := 'GIF';
|
||||||
|
Version := '89a';
|
||||||
|
ScreenWidth := Img.Width;
|
||||||
|
ScreenHeight := Img.Height;
|
||||||
|
b := lsb(fColorTableSize)-1;
|
||||||
|
Packedbit := (Packedbit and $8F) or (b shl 4); // Color Resolution
|
||||||
|
Packedbit := (Packedbit and $F7); // not sorted
|
||||||
|
Packedbit := (Packedbit and $F8) or b;
|
||||||
|
BackgroundColor := 0;
|
||||||
|
Packedbit := Packedbit or $80; // Global Color valid
|
||||||
|
end;
|
||||||
|
|
||||||
|
// make a descriptor record, color map for this image, and space for a pixel list
|
||||||
|
with fDescriptor do
|
||||||
|
begin
|
||||||
|
Left := 0;
|
||||||
|
Top := 0;
|
||||||
|
Width := Img.Width;
|
||||||
|
Height := Img.Height;
|
||||||
|
Packedbit := 0; // or $80 = but non local Color Table; or $40 = but not interlaced; or $20 but not sorted
|
||||||
|
end;
|
||||||
|
|
||||||
|
fPixelList := nil; // make empty pixel list
|
||||||
|
fPixelCount := Img.Width * Img.Height;
|
||||||
|
fPixelList := allocmem(fPixelCount);
|
||||||
|
if (fPixelList = nil) then OutOfMemoryError;
|
||||||
|
// and the color table
|
||||||
|
// the first call attempts to use all colors in the bitmap
|
||||||
|
// if too many colors, the 2nd call uses only most significat 8 bits of color
|
||||||
|
for ci:=0 to fPixelCount-1 do
|
||||||
|
begin
|
||||||
|
pptr := fPixelList + ci;
|
||||||
|
pptr^ := Chr(fPixels^[ci]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// set transparency for this image
|
||||||
|
with fGraphicsCtrlExt do
|
||||||
|
begin
|
||||||
|
BlockSize := 4;
|
||||||
|
Packedbit := $00;
|
||||||
|
ColorIndex := 0;
|
||||||
|
if (fTransparent) then
|
||||||
|
begin
|
||||||
|
n := FindColorIndex(fBackground);
|
||||||
|
if (n < 0) then n := FindColorIndex(fBackground and $00E0E0E0);
|
||||||
|
if (n < 0) then n := FindColorIndex(fBackground and $00C0E0E0);
|
||||||
|
if (n > -1) then
|
||||||
|
begin
|
||||||
|
Packedbit := Packedbit or $01; // transparent color given (Packedbit or $01)
|
||||||
|
ColorIndex := n; //transparent color index
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
DelayTime := 0;
|
||||||
|
Terminator := 0; // allways 0
|
||||||
|
end;
|
||||||
|
|
||||||
|
SaveToStream(Stream);
|
||||||
|
|
||||||
|
if (fPixelList <> nil) then FreeMem(fPixelList);
|
||||||
|
FreeMem(fPixels);
|
||||||
|
fPixels := nil;
|
||||||
|
end;
|
||||||
|
{$ENDREGION}
|
||||||
|
|
||||||
|
initialization
|
||||||
|
ImageHandlers.RegisterImageWriter ('GIF Graphics', 'gif', TFPWriterGif);
|
||||||
|
end.
|
166
components/lazbarcodes/examples/qrcodegenerator/main.lfm
Normal file
166
components/lazbarcodes/examples/qrcodegenerator/main.lfm
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
object MainForm: TMainForm
|
||||||
|
Left = 403
|
||||||
|
Height = 326
|
||||||
|
Top = 256
|
||||||
|
Width = 380
|
||||||
|
Caption = 'QRCode Generator'
|
||||||
|
ClientHeight = 326
|
||||||
|
ClientWidth = 380
|
||||||
|
Constraints.MinWidth = 300
|
||||||
|
OnActivate = FormActivate
|
||||||
|
OnDestroy = FormDestroy
|
||||||
|
LCLVersion = '2.3.0.0'
|
||||||
|
object btnCreateQR: TButton
|
||||||
|
AnchorSideLeft.Control = Owner
|
||||||
|
AnchorSideTop.Control = edText
|
||||||
|
AnchorSideTop.Side = asrBottom
|
||||||
|
Left = 8
|
||||||
|
Height = 25
|
||||||
|
Top = 64
|
||||||
|
Width = 108
|
||||||
|
AutoSize = True
|
||||||
|
BorderSpacing.Left = 8
|
||||||
|
BorderSpacing.Top = 16
|
||||||
|
Caption = 'Create QR code'
|
||||||
|
OnClick = btnCreateQRClick
|
||||||
|
TabOrder = 0
|
||||||
|
end
|
||||||
|
object edText: TEdit
|
||||||
|
AnchorSideLeft.Control = Owner
|
||||||
|
AnchorSideTop.Control = Label1
|
||||||
|
AnchorSideTop.Side = asrBottom
|
||||||
|
AnchorSideRight.Control = Owner
|
||||||
|
AnchorSideRight.Side = asrBottom
|
||||||
|
Left = 8
|
||||||
|
Height = 23
|
||||||
|
Top = 25
|
||||||
|
Width = 364
|
||||||
|
Anchors = [akTop, akLeft, akRight]
|
||||||
|
BorderSpacing.Left = 8
|
||||||
|
BorderSpacing.Top = 2
|
||||||
|
BorderSpacing.Right = 8
|
||||||
|
OnChange = edTextChange
|
||||||
|
TabOrder = 1
|
||||||
|
Text = 'https://www.lazarus-ide.org/'
|
||||||
|
end
|
||||||
|
object btnSaveAsGIF: TButton
|
||||||
|
AnchorSideLeft.Control = btnCreateQR
|
||||||
|
AnchorSideTop.Control = btnCreateQR
|
||||||
|
AnchorSideTop.Side = asrBottom
|
||||||
|
AnchorSideRight.Control = btnCreateQR
|
||||||
|
AnchorSideRight.Side = asrBottom
|
||||||
|
Left = 8
|
||||||
|
Height = 25
|
||||||
|
Top = 97
|
||||||
|
Width = 108
|
||||||
|
Anchors = [akTop, akLeft, akRight]
|
||||||
|
BorderSpacing.Top = 8
|
||||||
|
Caption = 'Save as GIF'
|
||||||
|
OnClick = btnSaveAsGIFClick
|
||||||
|
TabOrder = 2
|
||||||
|
Visible = False
|
||||||
|
end
|
||||||
|
object btnSaveAsBMP: TButton
|
||||||
|
AnchorSideLeft.Control = btnCreateQR
|
||||||
|
AnchorSideTop.Control = btnSaveAsGIF
|
||||||
|
AnchorSideTop.Side = asrBottom
|
||||||
|
AnchorSideRight.Control = btnCreateQR
|
||||||
|
AnchorSideRight.Side = asrBottom
|
||||||
|
Left = 8
|
||||||
|
Height = 25
|
||||||
|
Top = 130
|
||||||
|
Width = 108
|
||||||
|
Anchors = [akTop, akLeft, akRight]
|
||||||
|
BorderSpacing.Top = 8
|
||||||
|
Caption = 'Save as BMP'
|
||||||
|
OnClick = btnSaveAsBMPClick
|
||||||
|
TabOrder = 3
|
||||||
|
Visible = False
|
||||||
|
end
|
||||||
|
object StatusBar: TStatusBar
|
||||||
|
Left = 0
|
||||||
|
Height = 23
|
||||||
|
Top = 303
|
||||||
|
Width = 380
|
||||||
|
Panels = <>
|
||||||
|
end
|
||||||
|
object btnSaveAsPNG: TButton
|
||||||
|
AnchorSideLeft.Control = btnCreateQR
|
||||||
|
AnchorSideTop.Control = btnSaveAsBMP
|
||||||
|
AnchorSideTop.Side = asrBottom
|
||||||
|
AnchorSideRight.Control = btnCreateQR
|
||||||
|
AnchorSideRight.Side = asrBottom
|
||||||
|
Left = 8
|
||||||
|
Height = 25
|
||||||
|
Top = 163
|
||||||
|
Width = 108
|
||||||
|
Anchors = [akTop, akLeft, akRight]
|
||||||
|
BorderSpacing.Top = 8
|
||||||
|
Caption = 'Save as PNG'
|
||||||
|
OnClick = btnSaveAsPNGClick
|
||||||
|
TabOrder = 5
|
||||||
|
Visible = False
|
||||||
|
end
|
||||||
|
object btnSaveAsJPEG: TButton
|
||||||
|
AnchorSideLeft.Control = btnCreateQR
|
||||||
|
AnchorSideTop.Control = btnSaveAsPNG
|
||||||
|
AnchorSideTop.Side = asrBottom
|
||||||
|
AnchorSideRight.Control = btnCreateQR
|
||||||
|
AnchorSideRight.Side = asrBottom
|
||||||
|
Left = 8
|
||||||
|
Height = 25
|
||||||
|
Top = 196
|
||||||
|
Width = 108
|
||||||
|
Anchors = [akTop, akLeft, akRight]
|
||||||
|
BorderSpacing.Top = 8
|
||||||
|
Caption = 'Save as JPEG'
|
||||||
|
OnClick = btnSaveAsPNGClick
|
||||||
|
TabOrder = 6
|
||||||
|
Visible = False
|
||||||
|
end
|
||||||
|
object Label1: TLabel
|
||||||
|
AnchorSideLeft.Control = Owner
|
||||||
|
AnchorSideTop.Control = Owner
|
||||||
|
Left = 8
|
||||||
|
Height = 15
|
||||||
|
Top = 8
|
||||||
|
Width = 100
|
||||||
|
BorderSpacing.Left = 8
|
||||||
|
BorderSpacing.Top = 8
|
||||||
|
Caption = 'Text to be encoded'
|
||||||
|
end
|
||||||
|
object btnSaveAsSVG: TButton
|
||||||
|
AnchorSideLeft.Control = btnCreateQR
|
||||||
|
AnchorSideTop.Control = btnSaveAsJPEG
|
||||||
|
AnchorSideTop.Side = asrBottom
|
||||||
|
AnchorSideRight.Control = btnCreateQR
|
||||||
|
AnchorSideRight.Side = asrBottom
|
||||||
|
Left = 8
|
||||||
|
Height = 25
|
||||||
|
Top = 229
|
||||||
|
Width = 108
|
||||||
|
Anchors = [akTop, akLeft, akRight]
|
||||||
|
BorderSpacing.Top = 8
|
||||||
|
Caption = 'Save as SVG'
|
||||||
|
OnClick = btnSaveAsSVGClick
|
||||||
|
TabOrder = 7
|
||||||
|
Visible = False
|
||||||
|
end
|
||||||
|
object btnSaveAsEPS: TButton
|
||||||
|
AnchorSideLeft.Control = btnCreateQR
|
||||||
|
AnchorSideTop.Control = btnSaveAsSVG
|
||||||
|
AnchorSideTop.Side = asrBottom
|
||||||
|
AnchorSideRight.Control = btnCreateQR
|
||||||
|
AnchorSideRight.Side = asrBottom
|
||||||
|
Left = 8
|
||||||
|
Height = 25
|
||||||
|
Top = 262
|
||||||
|
Width = 108
|
||||||
|
Anchors = [akTop, akLeft, akRight]
|
||||||
|
BorderSpacing.Top = 8
|
||||||
|
Caption = 'Save as EPS'
|
||||||
|
OnClick = btnSaveAsEPSClick
|
||||||
|
TabOrder = 8
|
||||||
|
Visible = False
|
||||||
|
end
|
||||||
|
end
|
170
components/lazbarcodes/examples/qrcodegenerator/main.pas
Normal file
170
components/lazbarcodes/examples/qrcodegenerator/main.pas
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
unit main;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls,
|
||||||
|
ComCtrls, LCLIntf,
|
||||||
|
fpimage, fpWriteGIF,
|
||||||
|
ubarcodes;
|
||||||
|
|
||||||
|
type
|
||||||
|
TMyGifImage = class(TGifImage)
|
||||||
|
protected
|
||||||
|
class function GetWriterClass: TFPCustomImageWriterClass; override;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TMainForm }
|
||||||
|
|
||||||
|
TMainForm = class(TForm)
|
||||||
|
btnCreateQR: TButton;
|
||||||
|
btnSaveAsGIF: TButton;
|
||||||
|
btnSaveAsBMP: TButton;
|
||||||
|
btnSaveAsSVG: TButton;
|
||||||
|
btnSaveAsPNG: TButton;
|
||||||
|
btnSaveAsJPEG: TButton;
|
||||||
|
btnSaveAsEPS: TButton;
|
||||||
|
edText: TEdit;
|
||||||
|
Label1: TLabel;
|
||||||
|
StatusBar: TStatusBar;
|
||||||
|
procedure btnCreateQRClick(Sender: TObject);
|
||||||
|
procedure btnSaveAsEPSClick(Sender: TObject);
|
||||||
|
procedure btnSaveAsGIFClick(Sender: TObject);
|
||||||
|
procedure btnSaveAsBMPClick(Sender: TObject);
|
||||||
|
procedure btnSaveAsPNGClick(Sender: TObject);
|
||||||
|
procedure btnSaveAsSVGClick(Sender: TObject);
|
||||||
|
procedure edTextChange(Sender: TObject);
|
||||||
|
procedure FormActivate(Sender: TObject);
|
||||||
|
procedure FormDestroy(Sender: TObject);
|
||||||
|
private
|
||||||
|
QRCode: TBarcodeQR;
|
||||||
|
procedure EnableButtons(Enable: Boolean);
|
||||||
|
procedure SaveQRCodeToImage(AFileName: String; AImageClass: TFPImageBitmapClass);
|
||||||
|
|
||||||
|
public
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
MainForm: TMainForm;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
{$R *.lfm}
|
||||||
|
|
||||||
|
class function TMyGifImage.GetWriterClass: TFPCustomImageWriterClass;
|
||||||
|
begin
|
||||||
|
Result := TFPWriterGIF;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TMainForm }
|
||||||
|
|
||||||
|
procedure TMainForm.btnCreateQRClick(Sender: TObject);
|
||||||
|
begin
|
||||||
|
QRCode.Free;
|
||||||
|
QRCode := TBarcodeQR.Create(self);
|
||||||
|
QRCode.Text := edText.Text;
|
||||||
|
QRCode.Top := btnCreateQR.Top;
|
||||||
|
QRCode.Left := btnCreateQR.Left + btnCreateQR.Width + 10;
|
||||||
|
QRCode.Width := 168;
|
||||||
|
QRCode.Height := 168;
|
||||||
|
QRCode.Generate;
|
||||||
|
QRCode.Parent := self;
|
||||||
|
|
||||||
|
EnableButtons(true);
|
||||||
|
StatusBar.simpleText := 'QRCode generated.';
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TMainForm.btnSaveAsEPSClick(Sender: TObject);
|
||||||
|
var
|
||||||
|
fn: String;
|
||||||
|
begin
|
||||||
|
if QRCode = nil then
|
||||||
|
exit;
|
||||||
|
fn := 'qrcode.eps';
|
||||||
|
QRCode.SaveToEpsFile(fn);
|
||||||
|
StatusBar.SimpleText := 'QRCode saved to "' + fn + '".';
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TMainForm.btnSaveAsGIFClick(Sender: TObject);
|
||||||
|
begin
|
||||||
|
SaveQRCodeToImage('qrcode', TMyGifImage);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TMainForm.btnSaveAsBMPClick(Sender: TObject);
|
||||||
|
begin
|
||||||
|
SaveQRCodeToImage('qrcode', TBitmap);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TMainForm.btnSaveAsPNGClick(Sender: TObject);
|
||||||
|
begin
|
||||||
|
SaveQRCodeToImage('qrcode', TPortableNetworkGraphic);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TMainForm.btnSaveAsSVGClick(Sender: TObject);
|
||||||
|
var
|
||||||
|
fn: String;
|
||||||
|
begin
|
||||||
|
if QRCode = nil then
|
||||||
|
exit;
|
||||||
|
fn := 'qrcode.svg';
|
||||||
|
QRCode.SaveToSvgFile(fn);
|
||||||
|
StatusBar.SimpleText := 'QRCode saved to "' + fn + '".';
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TMainForm.edTextChange(Sender: TObject);
|
||||||
|
begin
|
||||||
|
EnableButtons(false);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TMainForm.FormActivate(Sender: TObject);
|
||||||
|
begin
|
||||||
|
ClientHeight := btnSaveAsEPS.Top + btnSaveAsEPS.Height + StatusBar.Height + 16;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TMainForm.EnableButtons(Enable: Boolean);
|
||||||
|
begin
|
||||||
|
btnSaveAsGIF.Visible := Enable;
|
||||||
|
btnSaveAsBMP.Visible := Enable;
|
||||||
|
btnSaveAsPNG.Visible := Enable;
|
||||||
|
btnSaveAsJPEG.Visible := Enable;
|
||||||
|
btnSaveAsSVG.Visible := Enable;
|
||||||
|
btnSaveAsEPS.Visible := Enable;
|
||||||
|
if not Enable then StatusBar.SimpleText := '';
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TMainForm.FormDestroy(Sender: TObject);
|
||||||
|
begin
|
||||||
|
QRCode.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TMainForm.SaveQRCodeToImage(AFileName: String; AImageClass: TFPImageBitmapClass);
|
||||||
|
var
|
||||||
|
ext: String;
|
||||||
|
begin
|
||||||
|
if QRCode = nil then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
if AImageClass = TBitmap then
|
||||||
|
ext := '.bmp'
|
||||||
|
else if AImageClass = TMyGifImage then
|
||||||
|
ext := '.gif'
|
||||||
|
else if AImageClass = TPortableNetworkGraphic then
|
||||||
|
ext := '.png'
|
||||||
|
else if AImageClass = TJpegImage then
|
||||||
|
ext := '.jpg'
|
||||||
|
else
|
||||||
|
raise Exception.Create('Image format not supported.');
|
||||||
|
|
||||||
|
AFileName := ChangeFileExt(AFileName, ext);
|
||||||
|
QRCode.SaveToFile(AFileName, AImageClass);
|
||||||
|
|
||||||
|
StatusBar.SimpleText := 'QRCode saved to "' + AFileName + '".';
|
||||||
|
end;
|
||||||
|
|
||||||
|
initialization
|
||||||
|
TPicture.RegisterFileFormat('.gif', 'gif', TMyGifImage);
|
||||||
|
end.
|
||||||
|
|
BIN
components/lazbarcodes/examples/qrcodegenerator/qrcodegen.ico
Normal file
BIN
components/lazbarcodes/examples/qrcodegenerator/qrcodegen.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 64 KiB |
@ -0,0 +1,87 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<CONFIG>
|
||||||
|
<ProjectOptions>
|
||||||
|
<Version Value="12"/>
|
||||||
|
<PathDelim Value="\"/>
|
||||||
|
<General>
|
||||||
|
<Flags>
|
||||||
|
<CompatibilityMode Value="True"/>
|
||||||
|
</Flags>
|
||||||
|
<SessionStorage Value="InProjectDir"/>
|
||||||
|
<Title Value="qrcodegen"/>
|
||||||
|
<Scaled Value="True"/>
|
||||||
|
<ResourceType Value="res"/>
|
||||||
|
<UseXPManifest Value="True"/>
|
||||||
|
<XPManifest>
|
||||||
|
<DpiAware Value="True"/>
|
||||||
|
</XPManifest>
|
||||||
|
<Icon Value="0"/>
|
||||||
|
</General>
|
||||||
|
<BuildModes Count="1">
|
||||||
|
<Item1 Name="Default" Default="True"/>
|
||||||
|
</BuildModes>
|
||||||
|
<PublishOptions>
|
||||||
|
<Version Value="2"/>
|
||||||
|
<UseFileFilters Value="True"/>
|
||||||
|
</PublishOptions>
|
||||||
|
<RunParams>
|
||||||
|
<FormatVersion Value="2"/>
|
||||||
|
</RunParams>
|
||||||
|
<RequiredPackages Count="2">
|
||||||
|
<Item1>
|
||||||
|
<PackageName Value="lazbarcodes"/>
|
||||||
|
</Item1>
|
||||||
|
<Item2>
|
||||||
|
<PackageName Value="LCL"/>
|
||||||
|
</Item2>
|
||||||
|
</RequiredPackages>
|
||||||
|
<Units Count="2">
|
||||||
|
<Unit0>
|
||||||
|
<Filename Value="qrcodegen.lpr"/>
|
||||||
|
<IsPartOfProject Value="True"/>
|
||||||
|
<UnitName Value="QRCodeGen"/>
|
||||||
|
</Unit0>
|
||||||
|
<Unit1>
|
||||||
|
<Filename Value="main.pas"/>
|
||||||
|
<IsPartOfProject Value="True"/>
|
||||||
|
<ComponentName Value="MainForm"/>
|
||||||
|
<HasResources Value="True"/>
|
||||||
|
<ResourceBaseClass Value="Form"/>
|
||||||
|
</Unit1>
|
||||||
|
</Units>
|
||||||
|
</ProjectOptions>
|
||||||
|
<CompilerOptions>
|
||||||
|
<Version Value="11"/>
|
||||||
|
<PathDelim Value="\"/>
|
||||||
|
<Target>
|
||||||
|
<Filename Value="qrcodegen"/>
|
||||||
|
</Target>
|
||||||
|
<SearchPaths>
|
||||||
|
<IncludeFiles Value="$(ProjOutDir)"/>
|
||||||
|
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
|
||||||
|
</SearchPaths>
|
||||||
|
<Linking>
|
||||||
|
<Debugging>
|
||||||
|
<DebugInfoType Value="dsDwarf3"/>
|
||||||
|
</Debugging>
|
||||||
|
<Options>
|
||||||
|
<Win32>
|
||||||
|
<GraphicApplication Value="True"/>
|
||||||
|
</Win32>
|
||||||
|
</Options>
|
||||||
|
</Linking>
|
||||||
|
</CompilerOptions>
|
||||||
|
<Debugging>
|
||||||
|
<Exceptions Count="3">
|
||||||
|
<Item1>
|
||||||
|
<Name Value="EAbort"/>
|
||||||
|
</Item1>
|
||||||
|
<Item2>
|
||||||
|
<Name Value="ECodetoolError"/>
|
||||||
|
</Item2>
|
||||||
|
<Item3>
|
||||||
|
<Name Value="EFOpenError"/>
|
||||||
|
</Item3>
|
||||||
|
</Exceptions>
|
||||||
|
</Debugging>
|
||||||
|
</CONFIG>
|
@ -0,0 +1,25 @@
|
|||||||
|
program QRCodeGen;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
|
uses
|
||||||
|
{$IFDEF UNIX}
|
||||||
|
cthreads,
|
||||||
|
{$ENDIF}
|
||||||
|
{$IFDEF HASAMIGA}
|
||||||
|
athreads,
|
||||||
|
{$ENDIF}
|
||||||
|
Interfaces, // this includes the LCL widgetset
|
||||||
|
Forms, main
|
||||||
|
{ you can add units after this };
|
||||||
|
|
||||||
|
{$R *.res}
|
||||||
|
|
||||||
|
begin
|
||||||
|
RequireDerivedFormResource:=True;
|
||||||
|
Application.Scaled:=True;
|
||||||
|
Application.Initialize;
|
||||||
|
Application.CreateForm(TMainForm, MainForm);
|
||||||
|
Application.Run;
|
||||||
|
end.
|
||||||
|
|
BIN
components/lazbarcodes/examples/qrcodegenerator/qrcodegen.res
Normal file
BIN
components/lazbarcodes/examples/qrcodegenerator/qrcodegen.res
Normal file
Binary file not shown.
Reference in New Issue
Block a user