123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- { 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.
|