mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-05-07 19:32:31 +02:00
220 lines
5.5 KiB
ObjectPascal
220 lines
5.5 KiB
ObjectPascal
{ Copyright (C) 2003 Mattias Gaertner
|
|
|
|
This library is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU Library General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or (at your
|
|
option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
|
|
for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; if not, write to the Free Software Foundation,
|
|
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
}
|
|
unit FPWriteJPEG;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, FPImage, JPEGLib, FPReadJPEG, JcAPIstd, JcAPImin, JDataDst,
|
|
JcParam, JError;
|
|
|
|
type
|
|
{ TFPWriterJPEG }
|
|
|
|
TFPJPEGCompressionQuality = 1..100; // 100 = best quality, 25 = pretty awful
|
|
|
|
TFPWriterJPEG = class(TFPCustomImageWriter)
|
|
private
|
|
FGrayscale: boolean;
|
|
FInfo: jpeg_compress_struct;
|
|
FError: jpeg_error_mgr;
|
|
FProgressiveEncoding: boolean;
|
|
FQuality: TFPJPEGCompressionQuality;
|
|
FProgressMgr: TFPJPEGProgressManager;
|
|
protected
|
|
procedure InternalWrite(Str: TStream; Img: TFPCustomImage); override;
|
|
public
|
|
constructor Create; override;
|
|
destructor Destroy; override;
|
|
property CompressionQuality: TFPJPEGCompressionQuality read FQuality write FQuality;
|
|
property ProgressiveEncoding: boolean read FProgressiveEncoding write FProgressiveEncoding;
|
|
property GrayScale: boolean read FGrayscale;
|
|
end;
|
|
|
|
implementation
|
|
|
|
procedure JPEGError(CurInfo: j_common_ptr);
|
|
begin
|
|
if CurInfo=nil then exit;
|
|
writeln('JPEGError ',CurInfo^.err^.msg_code,' ');
|
|
raise Exception.CreateFmt('JPEG error',[CurInfo^.err^.msg_code]);
|
|
end;
|
|
|
|
procedure EmitMessage(CurInfo: j_common_ptr; msg_level: Integer);
|
|
begin
|
|
if CurInfo=nil then exit;
|
|
if msg_level=0 then ;
|
|
end;
|
|
|
|
procedure OutputMessage(CurInfo: j_common_ptr);
|
|
begin
|
|
if CurInfo=nil then exit;
|
|
end;
|
|
|
|
procedure FormatMessage(CurInfo: j_common_ptr; var buffer: string);
|
|
begin
|
|
if CurInfo=nil then exit;
|
|
writeln('FormatMessage ',buffer);
|
|
end;
|
|
|
|
procedure ResetErrorMgr(CurInfo: j_common_ptr);
|
|
begin
|
|
if CurInfo=nil then exit;
|
|
CurInfo^.err^.num_warnings := 0;
|
|
CurInfo^.err^.msg_code := 0;
|
|
end;
|
|
|
|
var
|
|
jpeg_std_error: jpeg_error_mgr;
|
|
|
|
procedure ProgressCallback(CurInfo: j_common_ptr);
|
|
begin
|
|
if CurInfo=nil then exit;
|
|
// ToDo
|
|
end;
|
|
|
|
{ TFPWriterJPEG }
|
|
|
|
procedure TFPWriterJPEG.InternalWrite(Str: TStream; Img: TFPCustomImage);
|
|
var
|
|
MemStream: TMemoryStream;
|
|
Continue: Boolean;
|
|
|
|
procedure InitWriting;
|
|
begin
|
|
FillChar(FInfo, sizeof(FInfo), 0);
|
|
FError := jpeg_std_error;
|
|
FInfo.err := jerror.jpeg_std_error(FError);
|
|
|
|
jpeg_create_compress(@FInfo);
|
|
FProgressMgr.pub.progress_monitor := @ProgressCallback;
|
|
FProgressMgr.instance := Self;
|
|
FInfo.progress := @FProgressMgr;
|
|
end;
|
|
|
|
procedure SetDestination;
|
|
begin
|
|
if Str is TMemoryStream then
|
|
MemStream:=TMemoryStream(Str)
|
|
else
|
|
MemStream := TMemoryStream.Create;
|
|
jpeg_stdio_dest(@FInfo, @MemStream);
|
|
end;
|
|
|
|
procedure WriteHeader;
|
|
begin
|
|
FInfo.image_width := Img.Width;
|
|
FInfo.image_height := Img.Height;
|
|
FInfo.input_components := 3; // RGB has 3 components
|
|
FInfo.in_color_space := JCS_RGB;
|
|
if FGrayscale then
|
|
jpeg_set_colorspace(@FInfo, JCS_GRAYSCALE);
|
|
|
|
jpeg_set_defaults(@FInfo);
|
|
jpeg_set_quality(@FInfo, FQuality, True);
|
|
|
|
if ProgressiveEncoding then
|
|
jpeg_simple_progression(@FInfo);
|
|
end;
|
|
|
|
procedure WritePixels;
|
|
var
|
|
LinesWritten: Cardinal;
|
|
SampArray: JSAMPARRAY;
|
|
SampRow: JSAMPROW;
|
|
Color: TFPColor;
|
|
x: Integer;
|
|
y: Integer;
|
|
begin
|
|
Progress(psStarting, 0, False, Rect(0,0,0,0), '', Continue);
|
|
if not Continue then exit;
|
|
jpeg_start_compress(@FInfo, True);
|
|
|
|
// write one line per call
|
|
GetMem(SampArray,SizeOf(JSAMPROW));
|
|
GetMem(SampRow,FInfo.image_width*FInfo.input_components);
|
|
SampArray^[0]:=SampRow;
|
|
try
|
|
y:=0;
|
|
while (FInfo.next_scanline < FInfo.image_height) do begin
|
|
for x:=0 to FInfo.image_width-1 do begin
|
|
Color:=Img.Colors[x,y];
|
|
SampRow^[x*3+0]:=Color.Red shr 8;
|
|
SampRow^[x*3+1]:=Color.Green shr 8;
|
|
SampRow^[x*3+2]:=Color.Blue shr 8;
|
|
end;
|
|
LinesWritten := jpeg_write_scanlines(@FInfo, SampArray, 1);
|
|
if LinesWritten<1 then break;
|
|
inc(y);
|
|
end;
|
|
finally
|
|
FreeMem(SampRow);
|
|
FreeMem(SampArray);
|
|
end;
|
|
|
|
jpeg_finish_compress(@FInfo);
|
|
Progress(psEnding, 100, False, Rect(0,0,0,0), '', Continue);
|
|
end;
|
|
|
|
procedure EndWriting;
|
|
begin
|
|
jpeg_destroy_compress(@FInfo);
|
|
end;
|
|
|
|
begin
|
|
Continue := true;
|
|
MemStream:=nil;
|
|
try
|
|
InitWriting;
|
|
SetDestination;
|
|
WriteHeader;
|
|
WritePixels;
|
|
if MemStream<>Str then begin
|
|
MemStream.Position:=0;
|
|
Str.CopyFrom(MemStream,MemStream.Size);
|
|
end;
|
|
finally
|
|
EndWriting;
|
|
if MemStream<>Str then
|
|
MemStream.Free;
|
|
end;
|
|
end;
|
|
|
|
constructor TFPWriterJPEG.Create;
|
|
begin
|
|
inherited Create;
|
|
FQuality:=75;
|
|
end;
|
|
|
|
destructor TFPWriterJPEG.Destroy;
|
|
begin
|
|
inherited Destroy;
|
|
end;
|
|
|
|
initialization
|
|
with jpeg_std_error do begin
|
|
error_exit:=@JPEGError;
|
|
emit_message:=@EmitMessage;
|
|
output_message:=@OutputMessage;
|
|
format_message:=@FormatMessage;
|
|
reset_error_mgr:=@ResetErrorMgr;
|
|
end;
|
|
ImageHandlers.RegisterImageWriter ('JPEG graphics', 'jpg;jpeg', TFPWriterJPEG);
|
|
end.
|