fpwritejpeg.pas 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. { Copyright (C) 2003 Mattias Gaertner
  2. This library is free software; you can redistribute it and/or modify it
  3. under the terms of the GNU Library General Public License as published by
  4. the Free Software Foundation; either version 2 of the License, or (at your
  5. option) any later version.
  6. This program is distributed in the hope that it will be useful, but WITHOUT
  7. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  8. FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
  9. for more details.
  10. You should have received a copy of the GNU Library General Public License
  11. along with this library; if not, write to the Free Software Foundation,
  12. Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  13. }
  14. unit FPWriteJPEG;
  15. {$mode objfpc}{$H+}
  16. interface
  17. uses
  18. Classes, SysUtils, FPImage, JPEGLib, FPReadJPEG, JcAPIstd, JcAPImin, JDataDst,
  19. JcParam, JError;
  20. type
  21. { TFPWriterJPEG }
  22. TFPJPEGCompressionQuality = 1..100; // 100 = best quality, 25 = pretty awful
  23. TFPWriterJPEG = class(TFPCustomImageWriter)
  24. private
  25. FGrayscale: boolean;
  26. FInfo: jpeg_compress_struct;
  27. FError: jpeg_error_mgr;
  28. FProgressiveEncoding: boolean;
  29. FQuality: TFPJPEGCompressionQuality;
  30. FProgressMgr: TFPJPEGProgressManager;
  31. protected
  32. procedure InternalWrite(Str: TStream; Img: TFPCustomImage); override;
  33. public
  34. constructor Create; override;
  35. destructor Destroy; override;
  36. property CompressionQuality: TFPJPEGCompressionQuality read FQuality write FQuality;
  37. property ProgressiveEncoding: boolean read FProgressiveEncoding write FProgressiveEncoding;
  38. property GrayScale: boolean read FGrayscale;
  39. end;
  40. implementation
  41. procedure JPEGError(CurInfo: j_common_ptr);
  42. begin
  43. if CurInfo=nil then exit;
  44. writeln('JPEGError ',CurInfo^.err^.msg_code,' ');
  45. raise Exception.CreateFmt('JPEG error',[CurInfo^.err^.msg_code]);
  46. end;
  47. procedure EmitMessage(CurInfo: j_common_ptr; msg_level: Integer);
  48. begin
  49. if CurInfo=nil then exit;
  50. if msg_level=0 then ;
  51. end;
  52. procedure OutputMessage(CurInfo: j_common_ptr);
  53. begin
  54. if CurInfo=nil then exit;
  55. end;
  56. procedure FormatMessage(CurInfo: j_common_ptr; var buffer: string);
  57. begin
  58. if CurInfo=nil then exit;
  59. writeln('FormatMessage ',buffer);
  60. end;
  61. procedure ResetErrorMgr(CurInfo: j_common_ptr);
  62. begin
  63. if CurInfo=nil then exit;
  64. CurInfo^.err^.num_warnings := 0;
  65. CurInfo^.err^.msg_code := 0;
  66. end;
  67. var
  68. jpeg_std_error: jpeg_error_mgr;
  69. procedure ProgressCallback(CurInfo: j_common_ptr);
  70. begin
  71. if CurInfo=nil then exit;
  72. // ToDo
  73. end;
  74. { TFPWriterJPEG }
  75. procedure TFPWriterJPEG.InternalWrite(Str: TStream; Img: TFPCustomImage);
  76. var
  77. MemStream: TMemoryStream;
  78. Continue: Boolean;
  79. procedure InitWriting;
  80. begin
  81. FillChar(FInfo, sizeof(FInfo), 0);
  82. FError := jpeg_std_error;
  83. FInfo.err := jerror.jpeg_std_error(FError);
  84. jpeg_create_compress(@FInfo);
  85. FProgressMgr.pub.progress_monitor := @ProgressCallback;
  86. FProgressMgr.instance := Self;
  87. FInfo.progress := @FProgressMgr;
  88. end;
  89. procedure SetDestination;
  90. begin
  91. if Str is TMemoryStream then
  92. MemStream:=TMemoryStream(Str)
  93. else
  94. MemStream := TMemoryStream.Create;
  95. jpeg_stdio_dest(@FInfo, @MemStream);
  96. end;
  97. procedure WriteHeader;
  98. begin
  99. FInfo.image_width := Img.Width;
  100. FInfo.image_height := Img.Height;
  101. FInfo.input_components := 3; // RGB has 3 components
  102. FInfo.in_color_space := JCS_RGB;
  103. if FGrayscale then
  104. jpeg_set_colorspace(@FInfo, JCS_GRAYSCALE);
  105. jpeg_set_defaults(@FInfo);
  106. jpeg_set_quality(@FInfo, FQuality, True);
  107. if ProgressiveEncoding then
  108. jpeg_simple_progression(@FInfo);
  109. end;
  110. procedure WritePixels;
  111. var
  112. LinesWritten: Cardinal;
  113. SampArray: JSAMPARRAY;
  114. SampRow: JSAMPROW;
  115. Color: TFPColor;
  116. x: Integer;
  117. y: Integer;
  118. begin
  119. Progress(psStarting, 0, False, Rect(0,0,0,0), '', Continue);
  120. if not Continue then exit;
  121. jpeg_start_compress(@FInfo, True);
  122. // write one line per call
  123. GetMem(SampArray,SizeOf(JSAMPROW));
  124. GetMem(SampRow,FInfo.image_width*FInfo.input_components);
  125. SampArray^[0]:=SampRow;
  126. try
  127. y:=0;
  128. while (FInfo.next_scanline < FInfo.image_height) do begin
  129. for x:=0 to FInfo.image_width-1 do begin
  130. Color:=Img.Colors[x,y];
  131. SampRow^[x*3+0]:=Color.Red shr 8;
  132. SampRow^[x*3+1]:=Color.Green shr 8;
  133. SampRow^[x*3+2]:=Color.Blue shr 8;
  134. end;
  135. LinesWritten := jpeg_write_scanlines(@FInfo, SampArray, 1);
  136. if LinesWritten<1 then break;
  137. inc(y);
  138. end;
  139. finally
  140. FreeMem(SampRow);
  141. FreeMem(SampArray);
  142. end;
  143. jpeg_finish_compress(@FInfo);
  144. Progress(psEnding, 100, False, Rect(0,0,0,0), '', Continue);
  145. end;
  146. procedure EndWriting;
  147. begin
  148. jpeg_destroy_compress(@FInfo);
  149. end;
  150. begin
  151. Continue := true;
  152. MemStream:=nil;
  153. try
  154. InitWriting;
  155. SetDestination;
  156. WriteHeader;
  157. WritePixels;
  158. if MemStream<>Str then begin
  159. MemStream.Position:=0;
  160. Str.CopyFrom(MemStream,MemStream.Size);
  161. end;
  162. finally
  163. EndWriting;
  164. if MemStream<>Str then
  165. MemStream.Free;
  166. end;
  167. end;
  168. constructor TFPWriterJPEG.Create;
  169. begin
  170. inherited Create;
  171. FQuality:=75;
  172. end;
  173. destructor TFPWriterJPEG.Destroy;
  174. begin
  175. inherited Destroy;
  176. end;
  177. initialization
  178. with jpeg_std_error do begin
  179. error_exit:=@JPEGError;
  180. emit_message:=@EmitMessage;
  181. output_message:=@OutputMessage;
  182. format_message:=@FormatMessage;
  183. reset_error_mgr:=@ResetErrorMgr;
  184. end;
  185. ImageHandlers.RegisterImageWriter ('JPEG graphics', 'jpg;jpeg', TFPWriterJPEG);
  186. end.