Hello,
Thanks for this library!
Downloaded the latest "working" and all the images I load and save have the red and blue channels swapped.
If I put this:
image.LoadFromFile(Filename);
{basic transforms to ensure internal consistancy}
ConvertImage(image.ImageDataPointer^, ifA32R32G32B32F);
{work around Blue/Red channel swap bug}
image.SwapChannels(ChannelRed, ChannelBlue);
It seems to help.
I am Ubuntu, X64, Lazarus 0.9.30.2-0, FPC Version: 2.4.4, GTK2
Hello,
Did this work before you downloaded "working"?
Could you try ifA8R8G8B8 instead of ifA32R32G32B32F in the conversion?
What file formats have you loaded from/saved to?
Quote from: Galfar on 12 December 2011, 00:15:53
Hello,
Did this work before you downloaded "working"?
Could you try ifA8R8G8B8 instead of ifA32R32G32B32F in the conversion?
What file formats have you loaded from/saved to?
a) It wouldn't compile which is why I am using "working".
b) Will give said format a try in a bit and report back.
c) loading from gif, png, jpg, saving to png, jpg
d) just loaded 32-bit lazarus on my windows vm, it doesn't swap colors (what a painful experience..)
Have also discovered that "FileOpen" FHANDLE can hold "-1" on linux/x64 but shows up instead as 4294967295 when assigned -1 on W32 ???
Perhaps a CPU32 vs CPU64 thing?
Quote from: mjoyner@vbservices.net on 12 December 2011, 01:37:15
Quote from: Galfar on 12 December 2011, 00:15:53
Hello,
Did this work before you downloaded "working"?
Could you try ifA8R8G8B8 instead of ifA32R32G32B32F in the conversion?
Perhaps a CPU32 vs CPU64 thing?
changing format = no change in channel swap
I found out it is happening during an ASSIGN op:
tmpJPG := mkstemp;
image.SaveToFile('/tmp/test.jpg');
image.SaveToFile('/tmp/test.png');
jpg.AssignFromImageData(image.ImageDataPointer^);
jpg.Quality := Comics2ePubUI.seJpgQ.Value;
jpg.SaveToFile(tmpJPG);
I have tried:
jpg.Assign(image)
jpg.AssignFromImageData(image.ImageDataPointer^)
jpg.AssignFromImage(image)
....
OK, I think I found wherein it lies.
It is specifically the Assign and AssignFromImage*
const
{$J+}
image: TSingleImage = nil;
imageSwap: TSingleImage = nil;
png: TImagingPNG = nil;
jpg: TImagingJpeg = nil;
{$J-}
var
info: imgInfo;
tmpFile: UTF8String;
tmpJPG: UTF8String;
tmpPNG: UTF8String;
scaleByH: double;
scaleByW: double;
scaleBy: double;
newWidth: longint;
newHeight: longint;
begin
image := TSingleImage.Create;
png := TImagingPNG.Create;
jpg := TImagingJpeg.Create;
{work around Red/Blue swap on Assign issue, all further
assigns will swap the Red/Blue back to correctness, if the
bug does not exist (WIN32 for example), it is just extra
data being moved around with only a minor cpu impact}
png.AssignFromImage(image);
png.AssignToImageData(image.ImageDataPointer^);
The AssignTo does not seem to be impacted.
Look's like it is GTK2 interface or LCL RawImage related issue when converting
from LCL bitmap back to Imaging's image.
Just installed x64 Linux and started debugging...
Btw: Are you using classes from ImagingComponents unit just for saving?
Really not sure where your classes end and the LCL stuff begins. Just know that I read that I needed your classes to load image with automatic detection of image type and also using your functions for basic image rotate and scale operations at the moment.
Here is a copy of the subroutine.
function processImage(Filename: UTf8String): imgInfo;
const
{$J+}
image: TSingleImage = nil;
png: TImagingPNG = nil;
jpg: TImagingJpeg = nil;
{$J-}
var
info: imgInfo;
tmpFile: UTF8String;
tmpJPG: UTF8String;
tmpPNG: UTF8String;
scaleByH: double;
scaleByW: double;
scaleBy: double;
newWidth: longint;
newHeight: longint;
jpgQuality: longint;
begin
//info=imgInfo;
if UI.cbShowDebug.Checked then frmDebug.ShowOnTop;
if image = nil then begin
image := TSingleImage.Create;
png := TImagingPNG.Create;
jpg := TImagingJpeg.Create;
end;
{load image}
image.Clear;
frmDebug.memoDebug.Append(Filename);
image.LoadFromFile(Filename);
{basic transforms to ensure internal consistancy}
ConvertImage(image.ImageDataPointer^, ifA32R32G32B32F);
frmDebug.memoDebug.Append('Size: ' + IntToStr(image.Width) + 'x' +
IntToStr(image.Height));
{rotate check?}
if UI.cbRotate.Checked then if portrait then begin
if (image.Width > image.Height) then begin
UI.ProcessMessages;
RotateImage(image.ImageDataPointer^, 90);
frmDebug.memoDebug.Append('Rotated Size: ' + IntToStr(image.Width) +
'x' + IntToStr(image.Height));
end;
end else {landscape} if (image.Height > image.Width) then begin
UI.ProcessMessages;
RotateImage(image.ImageDataPointer^, -90);
frmDebug.memoDebug.Append('Rotated Size: ' + IntToStr(image.Width) +
'x' + IntToStr(image.Height));
end;
{rescale check?}
if UI.cbRescale.Checked then begin
{rescale down maxpect}
frmDebug.memoDebug.Append('Maxpect Size: ' + IntToStr(imageMaxpectWidth) +
'x' + IntToStr(imageMaxpectHeight));
UI.ProcessMessages;
scaleByW := imageMaxpectWidth / (image.Width * 1.0);
scaleByH := imageMaxpectHeight / (image.Height * 1.0);
if ((scaleByW < 1) or (scaleByH < 1)) then begin
if scaleByW < scaleByH then scaleBy := scaleByW
else
scaleBy := scaleByH;
newWidth := Round(scaleBy * image.Width);
newHeight := Round(scaleBy * image.Height);
ResizeImage(image.ImageDataPointer^, newWidth, newHeight, rfBicubic);
frmDebug.memoDebug.Append('New Size: ' + IntToStr(image.Width) +
'x' + IntToStr(image.Height));
end;
{rescale up maxpect}
if (scaleByW > 1) and (scaleByH > 1) then begin
if scaleByW < scaleByH then scaleBy := scaleByW
else
scaleBy := scaleByH;
newWidth := Round(scaleBy * image.Width);
newHeight := Round(scaleBy * image.Height);
ResizeImage(image.ImageDataPointer^, newWidth, newHeight, rfBicubic);
frmDebug.memoDebug.Append('New Size: ' + IntToStr(image.Width) +
'x' + IntToStr(image.Height));
end;
end;
{work around Red/Blue swap on Assign issue, all further
assigns will swap the Red/Blue back to correctness, if the
bug does not exist (WIN32 for example), it is just extra
data being moved around with only a minor cpu impact}
png.AssignFromImage(image);
png.AssignToImageData(image.ImageDataPointer^);
{save as temporary png file}
tmpPNG := mkstemp;
png.AssignFromImage(image);
png.CompressLevel := 9;
png.PreFilter := 6;
png.SaveToFile(tmpPNG);
{save as temporary jpg file}
tmpJPG := mkstemp;
jpg.AssignFromImage(image);
jpgQuality:=UI.seJpgQ.Value;
jpg.Quality := jpgQuality;
jpg.SaveToFile(tmpJPG);
if (FileSize(tmpPNG)>(UI.seJpgSize.Value*1024)) then begin
while (FileSize(tmpJPG) > UI.seJpgSize.Value*1024)
and (jpgQuality>=0) do begin
jpgQuality -= 1;
jpg.Quality := jpgQuality;
jpg.SaveToFile(tmpJPG);
end;
end;
{which is smaller?}
if (FileSize(tmpJPG) < FileSize(tmpPNG)) then tmpFile := tmpJPG
else
tmpFile := tmpPNG;
Result[0] := tmpFile;
Result[1] := DetermineFileFormat(tmpFile);
Result[2] := IntToStr(image.Width);
Result[3] := IntToStr(image.Height);
Result[4] := '';
end;
Bug was found and fixed. GTK2 uses different RB order than Win/Qt/Carbon widget sets and it
wasn't checked when converting from LCL bitmap back to Imaging. I'll update repository tomorrow.
Basically, LCL/VCL stuff was added to get ability to simply display Imaging's internal image formats
in GUI apps. If you just want to load/rotate/scale/save there's no need to use LCL stuff.
Btw, ifA32R32G32B32F seems like an overkill (128bits per pixel) that the file formats you use
for saving just convert back to 24/32bit.