Author Topic: Red/Blue color swap on save or load ? (bug)  (Read 225 times)

Offline mjoyner@vbservices.net

  • Imaging User
  • *
  • Posts: 5
    • View Profile
Red/Blue color swap on save or load ? (bug)
« on: 11 December 2011, 19:36:41 »
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:

Code: Pascal
  1.  
  2. image.LoadFromFile(Filename);
  3.  
  4.     {basic transforms to ensure internal consistancy}
  5.     ConvertImage(image.ImageDataPointer^, ifA32R32G32B32F);
  6.  
  7.     {work around Blue/Red channel swap bug}
  8.     image.SwapChannels(ChannelRed, ChannelBlue);
  9.  
  10.  

It seems to help.

I am Ubuntu, X64, Lazarus 0.9.30.2-0, FPC Version: 2.4.4, GTK2
« Last Edit: 11 December 2011, 19:44:45 by mjoyner@vbservices.net »

Offline Galfar

  • Administrator
  • Imaging User
  • *****
  • Posts: 320
    • View Profile
    • Galfar's Homepage
Re: Red/Blue color swap on save or load ? (bug)
« Reply #1 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?

Offline mjoyner@vbservices.net

  • Imaging User
  • *
  • Posts: 5
    • View Profile
Re: Red/Blue color swap on save or load ? (bug)
« Reply #2 on: 12 December 2011, 01:37:15 »
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?



Offline mjoyner@vbservices.net

  • Imaging User
  • *
  • Posts: 5
    • View Profile
Re: Red/Blue color swap on save or load ? (bug)
« Reply #3 on: 12 December 2011, 01:41:07 »
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


Offline mjoyner@vbservices.net

  • Imaging User
  • *
  • Posts: 5
    • View Profile
Re: Red/Blue color swap on save or load ? (bug)
« Reply #4 on: 12 December 2011, 04:27:02 »
I found out it is happening during an ASSIGN op:

Code: Pascal
  1.  
  2.     tmpJPG := mkstemp;
  3.     image.SaveToFile('/tmp/test.jpg');
  4.     image.SaveToFile('/tmp/test.png');
  5.     jpg.AssignFromImageData(image.ImageDataPointer^);
  6.     jpg.Quality := Comics2ePubUI.seJpgQ.Value;
  7.     jpg.SaveToFile(tmpJPG);                          
  8.  
  9.  

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*

Code: Pascal
  1.  
  2. const
  3.   {$J+}
  4.     image: TSingleImage = nil;
  5.     imageSwap: TSingleImage = nil;
  6.     png: TImagingPNG = nil;
  7.     jpg: TImagingJpeg = nil;
  8.   {$J-}
  9.   var
  10.     info: imgInfo;
  11.     tmpFile: UTF8String;
  12.     tmpJPG: UTF8String;
  13.     tmpPNG: UTF8String;
  14.     scaleByH: double;
  15.     scaleByW: double;
  16.     scaleBy: double;
  17.     newWidth: longint;
  18.     newHeight: longint;
  19.   begin
  20.       image := TSingleImage.Create;
  21.       png := TImagingPNG.Create;
  22.       jpg := TImagingJpeg.Create;      
  23.  
  24. {work around Red/Blue swap on Assign issue, all further
  25.     assigns will swap the Red/Blue back to correctness, if the
  26.     bug does not exist (WIN32 for example), it is just extra
  27.     data being moved around with only a minor cpu impact}
  28.  
  29.     png.AssignFromImage(image);
  30.     png.AssignToImageData(image.ImageDataPointer^);        
  31.  

The AssignTo does not seem to be impacted.

Offline Galfar

  • Administrator
  • Imaging User
  • *****
  • Posts: 320
    • View Profile
    • Galfar's Homepage
Re: Red/Blue color swap on save or load ? (bug)
« Reply #5 on: 13 December 2011, 18:55:38 »
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?

Offline mjoyner@vbservices.net

  • Imaging User
  • *
  • Posts: 5
    • View Profile
Re: Red/Blue color swap on save or load ? (bug)
« Reply #6 on: 14 December 2011, 01:22:01 »
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.

Code: Pascal
  1. function processImage(Filename: UTf8String): imgInfo;
  2.   const
  3.   {$J+}
  4.     image: TSingleImage = nil;
  5.     png: TImagingPNG = nil;
  6.     jpg: TImagingJpeg = nil;
  7.   {$J-}
  8.   var
  9.     info: imgInfo;
  10.     tmpFile: UTF8String;
  11.     tmpJPG: UTF8String;
  12.     tmpPNG: UTF8String;
  13.     scaleByH: double;
  14.     scaleByW: double;
  15.     scaleBy: double;
  16.     newWidth: longint;
  17.     newHeight: longint;
  18.     jpgQuality: longint;
  19.   begin
  20.     //info=imgInfo;
  21.     if UI.cbShowDebug.Checked then frmDebug.ShowOnTop;
  22.     if image = nil then begin
  23.       image := TSingleImage.Create;
  24.       png := TImagingPNG.Create;
  25.       jpg := TImagingJpeg.Create;
  26.       end;
  27.     {load image}
  28.     image.Clear;
  29.     frmDebug.memoDebug.Append(Filename);
  30.     image.LoadFromFile(Filename);
  31.  
  32.     {basic transforms to ensure internal consistancy}
  33.     ConvertImage(image.ImageDataPointer^, ifA32R32G32B32F);
  34.  
  35.     frmDebug.memoDebug.Append('Size: ' + IntToStr(image.Width) + 'x' +
  36.       IntToStr(image.Height));
  37.  
  38.     {rotate check?}
  39.     if UI.cbRotate.Checked then if portrait then begin
  40.         if (image.Width > image.Height) then begin
  41.           UI.ProcessMessages;
  42.           RotateImage(image.ImageDataPointer^, 90);
  43.           frmDebug.memoDebug.Append('Rotated Size: ' + IntToStr(image.Width) +
  44.             'x' + IntToStr(image.Height));
  45.           end;
  46.         end else {landscape} if (image.Height > image.Width) then begin
  47.           UI.ProcessMessages;
  48.           RotateImage(image.ImageDataPointer^, -90);
  49.           frmDebug.memoDebug.Append('Rotated Size: ' + IntToStr(image.Width) +
  50.             'x' + IntToStr(image.Height));
  51.           end;
  52.  
  53.     {rescale check?}
  54.     if UI.cbRescale.Checked then begin
  55.       {rescale down maxpect}
  56.       frmDebug.memoDebug.Append('Maxpect Size: ' + IntToStr(imageMaxpectWidth) +
  57.         'x' + IntToStr(imageMaxpectHeight));
  58.       UI.ProcessMessages;
  59.       scaleByW := imageMaxpectWidth / (image.Width * 1.0);
  60.       scaleByH := imageMaxpectHeight / (image.Height * 1.0);
  61.  
  62.       if ((scaleByW < 1) or (scaleByH < 1)) then begin
  63.         if scaleByW < scaleByH then scaleBy := scaleByW
  64.         else
  65.           scaleBy := scaleByH;
  66.         newWidth := Round(scaleBy * image.Width);
  67.         newHeight := Round(scaleBy * image.Height);
  68.         ResizeImage(image.ImageDataPointer^, newWidth, newHeight, rfBicubic);
  69.         frmDebug.memoDebug.Append('New Size: ' + IntToStr(image.Width) +
  70.           'x' + IntToStr(image.Height));
  71.         end;
  72.  
  73.       {rescale up maxpect}
  74.       if (scaleByW > 1) and (scaleByH > 1) then begin
  75.         if scaleByW < scaleByH then scaleBy := scaleByW
  76.         else
  77.           scaleBy := scaleByH;
  78.  
  79.         newWidth := Round(scaleBy * image.Width);
  80.         newHeight := Round(scaleBy * image.Height);
  81.         ResizeImage(image.ImageDataPointer^, newWidth, newHeight, rfBicubic);
  82.         frmDebug.memoDebug.Append('New Size: ' + IntToStr(image.Width) +
  83.           'x' + IntToStr(image.Height));
  84.  
  85.         end;
  86.       end;
  87.  
  88.     {work around Red/Blue swap on Assign issue, all further
  89.     assigns will swap the Red/Blue back to correctness, if the
  90.     bug does not exist (WIN32 for example), it is just extra
  91.     data being moved around with only a minor cpu impact}
  92.  
  93.     png.AssignFromImage(image);
  94.     png.AssignToImageData(image.ImageDataPointer^);
  95.  
  96.     {save as temporary png file}
  97.     tmpPNG := mkstemp;
  98.     png.AssignFromImage(image);
  99.     png.CompressLevel := 9;
  100.     png.PreFilter := 6;
  101.     png.SaveToFile(tmpPNG);
  102.  
  103.     {save as temporary jpg file}
  104.     tmpJPG := mkstemp;
  105.     jpg.AssignFromImage(image);
  106.     jpgQuality:=UI.seJpgQ.Value;
  107.  
  108.  
  109.     jpg.Quality := jpgQuality;
  110.     jpg.SaveToFile(tmpJPG);
  111.  
  112.     if  (FileSize(tmpPNG)>(UI.seJpgSize.Value*1024)) then begin
  113.         while (FileSize(tmpJPG) > UI.seJpgSize.Value*1024)
  114.         and (jpgQuality>=0) do begin
  115.             jpgQuality -= 1;
  116.             jpg.Quality := jpgQuality;
  117.             jpg.SaveToFile(tmpJPG);
  118.         end;
  119.     end;
  120.  
  121.  
  122.     {which is smaller?}
  123.     if (FileSize(tmpJPG) < FileSize(tmpPNG)) then tmpFile := tmpJPG
  124.     else
  125.       tmpFile := tmpPNG;
  126.     Result[0] := tmpFile;
  127.     Result[1] := DetermineFileFormat(tmpFile);
  128.     Result[2] := IntToStr(image.Width);
  129.     Result[3] := IntToStr(image.Height);
  130.     Result[4] := '';
  131.  
  132.   end;            
  133.  
« Last Edit: 14 December 2011, 01:27:27 by mjoyner@vbservices.net »

Offline Galfar

  • Administrator
  • Imaging User
  • *****
  • Posts: 320
    • View Profile
    • Galfar's Homepage
Re: Red/Blue color swap on save or load ? (bug)
« Reply #7 on: 20 December 2011, 03:54:31 »
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.