Skip to content

Commit b328a62

Browse files
committed
v1.4.4.0 Added basic webp support.
1 parent 4a7a14f commit b328a62

File tree

11 files changed

+1211
-38
lines changed

11 files changed

+1211
-38
lines changed

files/libwebp/libwebp.zip

2.18 MB
Binary file not shown.

files/libwebp/x64/libwebp.dll

-492 KB
Binary file not shown.

files/libwebp/x86/libwebp.dll

-387 KB
Binary file not shown.

src/ImageViewer.lpi

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
<PackageName Value="LCL"/>
5252
</Item2>
5353
</RequiredPackages>
54-
<Units Count="4">
54+
<Units Count="6">
5555
<Unit0>
5656
<Filename Value="ImageViewer.lpr"/>
5757
<IsPartOfProject Value="True"/>
@@ -80,6 +80,14 @@
8080
<ResourceBaseClass Value="Form"/>
8181
<UnitName Value="UAbout"/>
8282
</Unit3>
83+
<Unit4>
84+
<Filename Value="libwebp\fpreadwebp.pas"/>
85+
<IsPartOfProject Value="True"/>
86+
</Unit4>
87+
<Unit5>
88+
<Filename Value="libwebp\libwebp.pas"/>
89+
<IsPartOfProject Value="True"/>
90+
</Unit5>
8391
</Units>
8492
</ProjectOptions>
8593
<CompilerOptions>
@@ -90,6 +98,7 @@
9098
</Target>
9199
<SearchPaths>
92100
<IncludeFiles Value="$(ProjOutDir)"/>
101+
<OtherUnitFiles Value="libwebp"/>
93102
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
94103
</SearchPaths>
95104
<CodeGeneration>

src/ImageViewer.lpr

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@
66
{$IFDEF UNIX}{$IFDEF UseCThreads}
77
cthreads,
88
{$ENDIF}{$ENDIF}
9-
Interfaces, // this includes the LCL widgetset
10-
Forms, UMain, Ufullscreen, UAbout,
11-
LCLTranslator, lazutf8, Translations{$ifdef windows}, Windows{$endif};
9+
Interfaces, Forms,
10+
{$ifdef windows}
11+
libwebp, fpreadwebp, webpimage, Windows,
12+
{$endif}
13+
UMain, Ufullscreen, UAbout,
14+
LCLTranslator, lazutf8, Translations;
1215

1316
{$R *.res}
1417

src/libwebp/fpreadwebp.pas

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
unit fpreadwebp;
2+
3+
// libwebp (libwebp.dll wrapper. Implementation of reader, writter and TWEBPImage class)
4+
// copyright @LacaK
5+
// https://lacak.users.sourceforge.net/freepascal.html#libwebp
6+
7+
// reads WEBP images. Requires "libwebp" library.
8+
// writes WEBP images. Requires "libwebp" library.
9+
10+
11+
{$mode ObjFPC}{$H+}
12+
13+
{$DEFINE INCREMENTAL_DECODING}
14+
15+
interface
16+
17+
uses
18+
Classes, SysUtils, FPImage;
19+
20+
type
21+
22+
{ TFPReaderWEBP }
23+
24+
TFPReaderWEBP = class(TFPCustomImageReader)
25+
protected
26+
procedure InternalRead(Str: TStream; Img: TFPCustomImage); override;
27+
function InternalCheck(Str: TStream): boolean; override;
28+
end;
29+
30+
{ TFPWriterWEBP }
31+
32+
TFPWriterWEBP = class(TFPCustomImageWriter)
33+
private
34+
FQuality: integer;
35+
protected
36+
procedure InternalWrite(Str: TStream; Img: TFPCustomImage); override;
37+
public
38+
constructor Create; override;
39+
property CompressionQuality: integer read FQuality write FQuality;
40+
end;
41+
42+
implementation
43+
44+
uses
45+
libwebp;
46+
47+
{ TFPReaderWEBP }
48+
49+
// ImageRead -> InternalCheck -> InternalRead
50+
procedure TFPReaderWEBP.InternalRead(Str: TStream; Img: TFPCustomImage);
51+
function BGRAToFPColor(B,G,R,A: Byte): TFPColor; inline;
52+
begin
53+
with Result do
54+
begin
55+
Red :=(R shl 8) or R;
56+
Green :=(G shl 8) or G;
57+
Blue :=(B shl 8) or B;
58+
Alpha :=(A shl 8) or A;
59+
end;
60+
end;
61+
var
62+
w,h,x,y: integer;
63+
ptr, p: Puint8_t;
64+
ContProgress: boolean;
65+
{$IFDEF INCREMENTAL_DECODING}
66+
output: WebPDecBuffer;
67+
decoder: PWebPIDecoder;
68+
status: VP8StatusCode;
69+
buffer: array[0..4095] of Byte;
70+
data_size: integer;
71+
{$ELSE}
72+
MStream: TMemoryStream;
73+
{$ENDIF}
74+
begin
75+
ContProgress:=True;
76+
Progress(psStarting, 0, False, Rect(0,0,0,0), '', ContProgress);
77+
if not ContProgress then Exit;
78+
79+
{$IFDEF INCREMENTAL_DECODING}
80+
FillByte(buffer, SizeOf(buffer), 0);
81+
data_size := Str.Read(buffer, SizeOf(buffer));
82+
if (data_size>0) and (WebPGetInfo(@buffer, SizeOf(buffer), @w, @h) = 0) then
83+
raise FPImageException.Create('Wrong WEBP image format!')
84+
else begin
85+
Img.SetSize(w, h);
86+
ptr := GetMem(4*w*h);
87+
88+
WebPInitDecBuffer(@output);
89+
output.colorspace := MODE_BGRA;
90+
output.u.RGBA.rgba := ptr; // points to an external buffer
91+
output.u.RGBA.stride := 4*w;
92+
output.u.RGBA.size := 4*w*h;
93+
output.is_external_memory := 1;
94+
95+
decoder := WebPINewDecoder(@output);
96+
if decoder <> nil then
97+
while data_size > 0 do begin
98+
status := WebPIAppend(decoder, @buffer[0], data_size);
99+
if (status <> VP8_STATUS_OK) and (status <> VP8_STATUS_SUSPENDED) then
100+
break;
101+
data_size := Str.Read(buffer, SizeOf(buffer));
102+
end;
103+
104+
WebPFreeDecBuffer(@output);
105+
WebPIDelete(decoder); // config.output memory is preserved.
106+
end;
107+
{$ELSE}
108+
MStream := TMemoryStream.Create;
109+
try
110+
MStream.LoadFromStream(Str);
111+
112+
ptr := WebPDecodeBGRA(MStream.Memory, MStream.Size, @w, @h);
113+
if ptr = nil then
114+
raise FPImageException.Create('Wrong WEBP image format!')
115+
else begin
116+
Img.SetSize(w,h);
117+
118+
p := ptr;
119+
for y:=0 to h-1 do begin
120+
for x:=0 to w-1 do
121+
// TFPCustomImage provides only setter method? (Does not implements memory bitmap where BGRA values can be written directly)
122+
Img.Colors[x,y] := BGRAToFPColor(p[x shl 2], p[(x shl 2)+1], p[(x shl 2)+2], p[(x shl 2)+3]);
123+
Inc(p, w shl 2);
124+
end;
125+
end;
126+
finally
127+
MStream.Free;
128+
end;
129+
{$ENDIF}
130+
131+
// WEBP image is fully decoded into buffer pointed by "ptr"
132+
p := ptr;
133+
for y:=0 to h-1 do begin
134+
for x:=0 to w-1 do
135+
// TFPCustomImage provides only setter method? (Does not implements memory bitmap where BGRA values can be written directly)
136+
Img.Colors[x,y] := BGRAToFPColor(p[x shl 2], p[(x shl 2)+1], p[(x shl 2)+2], p[(x shl 2)+3]);
137+
Inc(p, w shl 2);
138+
end;
139+
140+
{$IFDEF INCREMENTAL_DECODING}
141+
FreeMem(ptr);
142+
{$ELSE}
143+
WebPFree(ptr);
144+
{$ENDIF}
145+
(*
146+
if WebPGetInfo(FStream.Memory, FStream.Size, @w, @h) <> 0 then begin
147+
Img.SetSize(w,h);
148+
bitmap := TBitmap.Create;
149+
bitmap.SetSize(w,h);
150+
bitmap.PixelFormat:=pf32bit; // BGRA
151+
if WebPDecodeBGRAInto(FStream.Memory, FStream.Size, bitmap.RawImage.Data, bitmap.RawImage.DataSize, bitmap.RawImage.Description.BytesPerLine) <> nil then
152+
Img.Assign(bitmap);
153+
bitmap.Free;
154+
end;
155+
*)
156+
Progress(FPimage.psEnding, 100, False, Rect(0,0,w,h), '', ContProgress);
157+
end;
158+
159+
function TFPReaderWEBP.InternalCheck(Str: TStream): boolean;
160+
var
161+
p: Int64;
162+
Buf: array[0..3] of AnsiChar;
163+
begin
164+
if Str=nil then Exit(False);
165+
p:=Str.Position;
166+
Str.Position:=0;
167+
Result := (Str.Read(Buf, 4)=4) and (Buf='RIFF');
168+
Str.Position:=8;
169+
Result := Result and (Str.Read(Buf, 4)=4) and (Buf='WEBP');
170+
Str.Position:=p;
171+
end;
172+
173+
174+
{ TFPWriterWEBP }
175+
176+
constructor TFPWriterWEBP.Create;
177+
begin
178+
inherited;
179+
FQuality := 100;
180+
end;
181+
182+
// TFPCustomImage.SaveToStream -> TFPCustomImageWriter.ImageWrite -> InternalWrite
183+
procedure TFPWriterWEBP.InternalWrite(Str: TStream; Img: TFPCustomImage);
184+
function FPColorToBGRA(c: TFPColor): LongWord; inline;
185+
begin
186+
Result := (c.Blue shr 8) or ((c.Green shr 8) shl 8) or ((c.Red shr 8) shl 16) or ((c.Alpha shr 8) shl 24);
187+
end;
188+
var
189+
bgra,p: PLongWord;
190+
x,y,data_size: integer;
191+
output: Puint8_t;
192+
begin
193+
// first construct BGRA buffer from Img.Colors (is there smarter approach?)
194+
// (TFPCustomImage provides only getter/setter for Colors property)
195+
bgra := GetMem(Img.Width*Img.Height*4);
196+
p := bgra;
197+
for y:=0 to Img.Height-1 do begin
198+
for x:=0 to Img.Width-1 do
199+
p[x] := FPColorToBGRA(Img.Colors[x,y]);
200+
Inc(p, Img.Width);
201+
end;
202+
// then encode WEBP image
203+
data_size := WebPEncodeBGRA(Puint8_t(bgra), Img.Width, Img.Height, Img.Width*4, FQuality, output);
204+
// and save to stream
205+
Str.Write(output^, data_size);
206+
WebPFree(output);
207+
FreeMem(bgra);
208+
end;
209+
210+
211+
initialization
212+
if LoadLibwebp() then begin
213+
ImageHandlers.RegisterImageReader('WEBP Graphics', 'webp', TFPReaderWEBP);
214+
ImageHandlers.RegisterImageWriter('WEBP Graphics', 'webp', TFPWriterWEBP);
215+
end;
216+
217+
end.
218+

0 commit comments

Comments
 (0)