• Welcome to Vampyre Imaging Library Forum. Please login or sign up.
 

Red/Blue color swap on save or load ? (bug)

Started by mjoyner@vbservices.net, 11 December 2011, 19:36:41

Previous topic - Next topic

mjoyner@vbservices.net

11 December 2011, 19:36:41 Last Edit: 11 December 2011, 19:44:45 by mjoyner@vbservices.net
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) Select


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

Galfar

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?

mjoyner@vbservices.net

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?



mjoyner@vbservices.net

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


mjoyner@vbservices.net

I found out it is happening during an ASSIGN op:

Code (pascal) Select


    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*

Code (pascal) Select


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.

Galfar

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?

mjoyner@vbservices.net

14 December 2011, 01:22:01 #6 Last Edit: 14 December 2011, 01:27:27 by mjoyner@vbservices.net
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) Select

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;           

Galfar

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.

Quick Reply

With Quick-Reply you can write a post when viewing a topic without loading a new page. You can still use bulletin board code and smileys as you would in a normal post.

Name:
Email:

Shortcuts: ALT+S save/post or ALT+P preview

SMF spam blocked by CleanTalk