mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-05 06:38:00 +02:00
JPEG: support custom CMYK conversions and reading custom APPn headers
This commit is contained in:
parent
84a852bc13
commit
0d988f2c96
@ -79,6 +79,7 @@ type
|
|||||||
FProgressiveEncoding: boolean;
|
FProgressiveEncoding: boolean;
|
||||||
FError: jpeg_error_mgr;
|
FError: jpeg_error_mgr;
|
||||||
FProgressMgr: TFPJPEGProgressManager;
|
FProgressMgr: TFPJPEGProgressManager;
|
||||||
|
FExtensions: jpeg_extensions;
|
||||||
FInfo: jpeg_decompress_struct;
|
FInfo: jpeg_decompress_struct;
|
||||||
FScale: TJPEGScale;
|
FScale: TJPEGScale;
|
||||||
FPerformance: TJPEGReadPerformance;
|
FPerformance: TJPEGReadPerformance;
|
||||||
@ -87,6 +88,10 @@ type
|
|||||||
procedure SetPerformance(const AValue: TJPEGReadPerformance);
|
procedure SetPerformance(const AValue: TJPEGReadPerformance);
|
||||||
procedure SetSmoothing(const AValue: boolean);
|
procedure SetSmoothing(const AValue: boolean);
|
||||||
protected
|
protected
|
||||||
|
function CMYKToRGB(const C, M, Y, K: Byte): TFPColor; virtual;
|
||||||
|
procedure ReadExtAPPn(Marker: int; var Header: array of JOCTET; HeaderLen: uint;
|
||||||
|
var Remaining: INT32; ReadData: jpeg_ext_appn_readdata); virtual;
|
||||||
|
|
||||||
procedure ReadHeader(Str: TStream; Img: TFPCustomImage); virtual;
|
procedure ReadHeader(Str: TStream; Img: TFPCustomImage); virtual;
|
||||||
procedure ReadPixels(Str: TStream; Img: TFPCustomImage); virtual;
|
procedure ReadPixels(Str: TStream; Img: TFPCustomImage); virtual;
|
||||||
procedure InternalRead(Str: TStream; Img: TFPCustomImage); override;
|
procedure InternalRead(Str: TStream; Img: TFPCustomImage); override;
|
||||||
@ -202,6 +207,14 @@ begin
|
|||||||
// ToDo
|
// ToDo
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure ReadExtAPPnCallback(cinfo : j_decompress_ptr; marker : int; var header : array of JOCTET; headerlen : uint;
|
||||||
|
var remaining : int32; readdata: jpeg_ext_appn_readdata);
|
||||||
|
begin
|
||||||
|
if (cinfo=nil) or (cinfo^.client_data=nil) then exit;
|
||||||
|
|
||||||
|
TFPReaderJPEG(cinfo^.client_data).ReadExtAPPn(marker, header, headerlen, remaining, readdata);
|
||||||
|
end;
|
||||||
|
|
||||||
{ TFPReaderJPEG }
|
{ TFPReaderJPEG }
|
||||||
|
|
||||||
procedure TFPReaderJPEG.SetSmoothing(const AValue: boolean);
|
procedure TFPReaderJPEG.SetSmoothing(const AValue: boolean);
|
||||||
@ -210,6 +223,11 @@ begin
|
|||||||
FSmoothing:=AValue;
|
FSmoothing:=AValue;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TFPReaderJPEG.ReadExtAPPn(Marker: int; var Header: array of JOCTET; HeaderLen: uint; var Remaining: INT32; ReadData: jpeg_ext_appn_readdata);
|
||||||
|
begin
|
||||||
|
// override to read extended APPn data
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TFPReaderJPEG.SetPerformance(const AValue: TJPEGReadPerformance);
|
procedure TFPReaderJPEG.SetPerformance(const AValue: TJPEGReadPerformance);
|
||||||
begin
|
begin
|
||||||
if FPerformance=AValue then exit;
|
if FPerformance=AValue then exit;
|
||||||
@ -347,21 +365,6 @@ var
|
|||||||
Img.Colors[P.x, P.y] := C;
|
Img.Colors[P.x, P.y] := C;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function CorrectCMYK(const C: TFPColor): TFPColor;
|
|
||||||
var
|
|
||||||
MinColor: word;
|
|
||||||
begin
|
|
||||||
// accuracy not 100%
|
|
||||||
if C.red<C.green then MinColor:=C.red
|
|
||||||
else MinColor:= C.green;
|
|
||||||
if C.blue<MinColor then MinColor:= C.blue;
|
|
||||||
if MinColor+ C.alpha>$FF then MinColor:=$FF-C.alpha;
|
|
||||||
Result.red:=(C.red-MinColor) shl 8;
|
|
||||||
Result.green:=(C.green-MinColor) shl 8;
|
|
||||||
Result.blue:=(C.blue-MinColor) shl 8;
|
|
||||||
Result.alpha:=alphaOpaque;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure OutputScanLines();
|
procedure OutputScanLines();
|
||||||
var
|
var
|
||||||
x: integer;
|
x: integer;
|
||||||
@ -428,12 +431,7 @@ var
|
|||||||
end;
|
end;
|
||||||
JCS_CMYK, JCS_YCCK:
|
JCS_CMYK, JCS_YCCK:
|
||||||
for x:=0 to FInfo.output_width-1 do
|
for x:=0 to FInfo.output_width-1 do
|
||||||
begin
|
SetPixel(x, y, CMYKToRGB(SampRow^[x*4+0], SampRow^[x*4+1], SampRow^[x*4+2], SampRow^[x*4+3]));
|
||||||
//SetPixel(x, y, CorrectCMYK(TFPColor.New(SampRow^[x*4+0], SampRow^[x*4+1], SampRow^[x*4+2], SampRow^[x*4+3])));
|
|
||||||
|
|
||||||
cmyk :=TStdCMYK.New(SampRow^[x*4+0], SampRow^[x*4+1], SampRow^[x*4+2], SampRow^[x*4+3]);
|
|
||||||
SetPixel(x, y, cmyk.ToExpandedPixel.ToFPColor(false));
|
|
||||||
end;
|
|
||||||
else
|
else
|
||||||
for x:=0 to FInfo.output_width-1 do begin
|
for x:=0 to FInfo.output_width-1 do begin
|
||||||
Color.Red:=SampRow^[x*3+0] shl 8;
|
Color.Red:=SampRow^[x*3+0] shl 8;
|
||||||
@ -593,6 +591,11 @@ begin
|
|||||||
MemStream.Position:=0;
|
MemStream.Position:=0;
|
||||||
jpeg_stdio_src(@FInfo, @MemStream);
|
jpeg_stdio_src(@FInfo, @MemStream);
|
||||||
|
|
||||||
|
FInfo.extensions := @FExtensions;
|
||||||
|
FExtensions.read_ext_appn := @ReadExtAPPnCallback;
|
||||||
|
|
||||||
|
FInfo.client_data := Self;
|
||||||
|
|
||||||
ReadHeader(MemStream, Img);
|
ReadHeader(MemStream, Img);
|
||||||
ReadPixels(MemStream, Img);
|
ReadPixels(MemStream, Img);
|
||||||
finally
|
finally
|
||||||
@ -646,6 +649,14 @@ begin
|
|||||||
inherited Create;
|
inherited Create;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TFPReaderJPEG.CMYKToRGB(const C, M, Y, K: Byte): TFPColor;
|
||||||
|
begin
|
||||||
|
Result.Red := ((C*K) div 255) shl 8;
|
||||||
|
Result.Green := ((M*K) div 255) shl 8;
|
||||||
|
Result.Blue := ((Y*K) div 255) shl 8;
|
||||||
|
Result.Alpha := alphaOpaque;
|
||||||
|
end;
|
||||||
|
|
||||||
destructor TFPReaderJPEG.Destroy;
|
destructor TFPReaderJPEG.Destroy;
|
||||||
begin
|
begin
|
||||||
inherited Destroy;
|
inherited Destroy;
|
||||||
|
@ -17,6 +17,7 @@ Unit JdMarker;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
{$I jconfig.inc}
|
{$I jconfig.inc}
|
||||||
|
{$modeswitch nestedprocvars}
|
||||||
|
|
||||||
{$IFDEF FPC_DOTTEDUNITS}
|
{$IFDEF FPC_DOTTEDUNITS}
|
||||||
uses
|
uses
|
||||||
@ -1665,13 +1666,13 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
{LOCAL}
|
{LOCAL}
|
||||||
function examine_app1 (cinfo : j_decompress_ptr;
|
procedure examine_app1 (cinfo : j_decompress_ptr;
|
||||||
var header : array of JOCTET;
|
var header : array of JOCTET;
|
||||||
headerlen : uint;
|
headerlen : uint;
|
||||||
var remaining : INT32;
|
var remaining : INT32;
|
||||||
datasrc : jpeg_source_mgr_ptr;
|
datasrc : jpeg_source_mgr_ptr;
|
||||||
var next_input_byte : JOCTETptr;
|
var next_input_byte : JOCTETptr;
|
||||||
var bytes_in_buffer : size_t): Boolean;
|
var bytes_in_buffer : size_t);
|
||||||
|
|
||||||
{ Read Exif marker.
|
{ Read Exif marker.
|
||||||
headerlen is # of bytes at header[], remaining is length of rest of marker header.
|
headerlen is # of bytes at header[], remaining is length of rest of marker header.
|
||||||
@ -1790,7 +1791,7 @@ begin
|
|||||||
|
|
||||||
// read data
|
// read data
|
||||||
if not Read16(numRecords) then
|
if not Read16(numRecords) then
|
||||||
Exit(False);
|
Exit;
|
||||||
|
|
||||||
for i:=1 to numRecords do
|
for i:=1 to numRecords do
|
||||||
begin
|
begin
|
||||||
@ -1820,6 +1821,12 @@ begin
|
|||||||
my_marker_ptr(cinfo^.marker)^.handle_exif_tag(cinfo, ifdRec, BigEndian, data, EXIF_TAGPARENT_PRIMARY);
|
my_marker_ptr(cinfo^.marker)^.handle_exif_tag(cinfo, ifdRec, BigEndian, data, EXIF_TAGPARENT_PRIMARY);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
end else
|
||||||
|
if Assigned(cinfo.extensions) and Assigned(cinfo.extensions^.read_ext_appn) and (headerlen>0) then
|
||||||
|
begin
|
||||||
|
BigEndian := False;
|
||||||
|
Offset := APP1_HEADER_LEN;
|
||||||
|
cinfo.extensions^.read_ext_appn(cinfo, M_APP1, header, headerlen, remaining, Read);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ Unit JPEGLib;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
{$I jconfig.inc}
|
{$I jconfig.inc}
|
||||||
|
{$modeswitch nestedprocvars}
|
||||||
|
|
||||||
{ First we include the configuration files that record how this
|
{ First we include the configuration files that record how this
|
||||||
installation of the JPEG library is set up. jconfig.h can be
|
installation of the JPEG library is set up. jconfig.h can be
|
||||||
@ -719,6 +720,15 @@ type
|
|||||||
new_color_map : procedure(cinfo : j_decompress_ptr);
|
new_color_map : procedure(cinfo : j_decompress_ptr);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ JPEG extensions }
|
||||||
|
jpeg_ext_appn_readdata = function (const Buffer: Pointer; numtoread: uint): Boolean is nested;
|
||||||
|
jpeg_extensions_ptr = ^jpeg_extensions;
|
||||||
|
jpeg_extensions = record
|
||||||
|
// read extended (unknown) APPn data
|
||||||
|
read_ext_appn : procedure(cinfo : j_decompress_ptr; marker : int; var header : array of JOCTET; headerlen : uint;
|
||||||
|
var remaining : int32; readdata: jpeg_ext_appn_readdata);
|
||||||
|
end;
|
||||||
|
|
||||||
{int8array = Array[0..8-1] of int;}
|
{int8array = Array[0..8-1] of int;}
|
||||||
int8array = Array[0..8-1] of longint; { for TP FormatStr }
|
int8array = Array[0..8-1] of longint; { for TP FormatStr }
|
||||||
TFormatCallback = procedure (cinfo : j_common_ptr; var buffer : shortstring);
|
TFormatCallback = procedure (cinfo : j_common_ptr; var buffer : shortstring);
|
||||||
@ -1280,6 +1290,7 @@ type
|
|||||||
upsample : jpeg_upsampler_ptr;
|
upsample : jpeg_upsampler_ptr;
|
||||||
cconvert : jpeg_color_deconverter_ptr;
|
cconvert : jpeg_color_deconverter_ptr;
|
||||||
cquantize : jpeg_color_quantizer_ptr;
|
cquantize : jpeg_color_quantizer_ptr;
|
||||||
|
extensions : jpeg_extensions_ptr;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ Decompression startup: read start of JPEG datastream to see what's there
|
{ Decompression startup: read start of JPEG datastream to see what's there
|
||||||
|
Loading…
Reference in New Issue
Block a user