SVGIconImageList icon indicating copy to clipboard operation
SVGIconImageList copied to clipboard

Blueish tint on Android and MacOS-X

Open birbilis opened this issue 3 years ago • 66 comments

I see blueish tint on Android when using the latest TSVGIconImageList from GetIt Package Manager

Windows: TortoiseAndTheHare_EditMode_StructureView en

Android: Tortoise and the Hare en_StructureView_EditMode-Samsung Galaxy Tab S8-12 0

The app is at https://github.com/zoomicon/READCOM_App

Apart from using TSVGIconImage for the SVG images in the stories, I use TSVGIconImageList for the app icons. All those are tinted. However, stories that contain bitmap images show fine, so it's something with the SVG rendering

I think it uses Image32 for rendering now (judging from a little debugging). Is there any known issue with that? How can I tell your library to use Skia SVG renderer instead? (or is there other engine alternative on Android too?) Do I need to install Skia4Delphi too and right click my project and enabled Skia (to added needed lib to deployment)?

UPDATE: the same tint appears on MacOS-X (those are supposed to be English/Greek/Italian/Portuguese/Spanish flags in the image) image

Is it something related to RGB versus BGR? Is Image32 also being used by default on OS-X?

birbilis avatar May 15 '22 20:05 birbilis

Note that bitmap images (rendered via FMX) look fine image

birbilis avatar May 19 '22 16:05 birbilis

Please try to restore previous version of Img32.SVG.Reader that contains:

    if (fillColor = clCurrent) then
      {$IF Defined(MACOS) or Defined(MACOSX)}
      drawDat.fillColor := SwapRedBlue(thisElement.fReader.currentColor)
      {$ELSE}
      drawDat.fillColor := thisElement.fReader.currentColor
      {$IFEND}
    else if (fillColor <> clInvalid) then
      {$IF Defined(MACOS) or Defined(MACOSX)}
      drawDat.fillColor := SwapRedBlue(fillColor);
      {$ELSE}
      drawDat.fillColor := fillColor;
      {$IFEND}
    if fillOpacity <> InvalidD then
      drawDat.fillOpacity := fillOpacity;
    if (fillEl <> '') then
      drawDat.fillEl := fillEl;
    if (strokeColor = clCurrent) then
      {$IF Defined(MACOS) or Defined(MACOSX)}
      drawDat.strokeColor := SwapRedBlue(thisElement.fReader.currentColor)
      {$ELSE}
      drawDat.strokeColor := thisElement.fReader.currentColor
      {$IFEND}
    else if strokeColor <> clInvalid then
      {$IF Defined(MACOS) or Defined(MACOSX)}
      drawDat.strokeColor := SwapRedBlue(strokeColor);
      {$ELSE}
      drawDat.strokeColor := strokeColor;
      {$IFEND}

because it was lost during update to Image32 4.11 version. Then give me a feed-back if it works, so i can restore this fix and notify Angus Johnson, the author of Image32. Thanks.

carloBarazzetta avatar May 19 '22 17:05 carloBarazzetta

problem is I'm using the GetIt version (not sure if GetIt allows one to rollback to previous versions). Can I patch it by including my copy of that unit (I can get it from their version control) in the uses clause of the app? I haven't tried building your library, was afraid I'd lose time trying to pull in all dependencies

birbilis avatar May 19 '22 18:05 birbilis

another problem I see is that this code (which looks promising btw) check if it's targetting MACOS-X, but I don't see Android or iOS mentioned (at Android it's the same issue and I suspect it's on iOS too).

birbilis avatar May 19 '22 18:05 birbilis

Unfortunately, I don't have mobile devices on which to test. I advise you to install the library by cloning the repo from Git: the installation is simple, just open the package group do the build / install of the packages, as explained here: Now you can develop by compiling the sources directly and trying to make changes to fix the color problem on the different devices.

There is another place to adjust color that affect also ANDROID platform, into FMX.Image32SVG:

function AlphaToColor32(AlphaColor: TAlphaColor): TColor32;
var
  res: TARGB;
begin
  res.A := TAlphaColorRec(AlphaColor).A;
  res.R := TAlphaColorRec(AlphaColor).R;
  res.G := TAlphaColorRec(AlphaColor).G;
  res.B := TAlphaColorRec(AlphaColor).B;
  Result := res.Color;
{$IF Defined(ANDROID) or Defined(MACOS) or Defined(MACOSX)}
  Result := SwapRedBlue(Result);
{$IFEND}
end;

carloBarazzetta avatar May 20 '22 10:05 carloBarazzetta

thanks, will take a look

btw, an easy way to test is to upload an APK at https://www.browserstack.com/android-testing (note one needs to create a certificate from inside Delphi to sign the resulting .apk, else BrowserStack won't install it)

birbilis avatar May 20 '22 19:05 birbilis

Looking at that code snippets you shared, it seems they were loading the RGB as BGR (but only on OS-X) and then they were swapping again back to RGB or something (this time both on Android and OS-X).

So their original code (without the code that was removed from the SVG loader) would work on OS-X (had double inversion that was self-canceling), but on Android I guess. Now that they removed that they have it broken both on OS-X and Android (then probably on iOS it may work, will check on the iOS emulator)

birbilis avatar May 23 '22 08:05 birbilis

Started looking at it, one quick comment I have is that I feel the .groupproj should contain the demo projects too for convenience (so that one can easily test a change they did), or could add extra groupproj with everything (packages and demos), since the existing is called "SVGIconImageListGroupPackages". Not sure if GetIt needs that groupproj to only contain the packages or something, plus hope if extra is added with everything that GetIt isn't confused (e.g. losing time to build all demos or something)

birbilis avatar May 24 '22 10:05 birbilis

I can confirm that the issue occurs on Android with the SVGIconImageListDemoFMX project too (here I project via Miracast [wifi] from Android to Windows 11):

image

(I also notice some layout glitch at the FixedColor checkbox and the color dropdown [and its dropdown arrow] under it)

To build/run on Android, I had to right click the Libraries not and select "Revert System Files to Default":

image

birbilis avatar May 24 '22 11:05 birbilis

the issue isn't probably with loading the SVGs, but with rendering them, since if I play with the Fixed Color option at that demo, I see other color result (though I'm not sure how the Fixed Color functionality is implemented [if it "reloads" the SVG from a modified source or if it changes it in memory without invoking an SVG reader/parser again]):

image

birbilis avatar May 24 '22 11:05 birbilis

making AlphaToColor32 not call SwapRedBlue didn't work, but making SwapRedBlue not do anything (comment out the swapping commands) did work:

function SwapRedBlue(color: TColor32): TColor32;
var
  c: array[0..3] of byte absolute color;
  r: array[0..3] of byte absolute Result;
begin
  result := color;
  //r[0] := c[2];
  //r[2] := c[0];
end;

probably though that method is needed to be there (don't want to make it do nothing), so will look into it a bit more to see who calls it

birbilis avatar May 24 '22 17:05 birbilis

searching for the symbol with find in files gives:

opening one by one seems actual callers are these methods:

  • RgbToHsl at Img32.pas(1229)
  • HslToRgb at Img32.pas(1292)
  • AlphaToColor32 at FMX.Img32SVG.pas(83) - commenting it out there didn't do the trick as I mentioned above and the most suspicious one:
  • UTF8StringToColor32 at Img32.SVG.Core.pas(1191)

fixing the last one also does the trick (instead of making SwapRedBlue do nothing), but it has a conditional check for Android only, so have to check why MacOS-X also has the issue and if this fixes it for it too, or it needs fix also at other place

birbilis avatar May 24 '22 18:05 birbilis

I forwarded the issue to Angus Johnson, author of Image32...

carloBarazzetta avatar May 24 '22 18:05 carloBarazzetta

thanks, will post here any more findings since I'll try on OS-X too later on today

birbilis avatar May 24 '22 18:05 birbilis

note that just adding to SVGIconImageListDemoFMX project the patched Img32.SVG.Core.pas (with commented out SwapRedBlue call at line 1191) does the trick on Android, even with the GetIt version of SVGIconImageList

{$IFDEF ANDROID}
//color := SwapRedBlue(color); //TODO: this fixes Blueish SVG color tint (RGB-BGR substitution) on Android, but should try to fix OS-X too (https://github.com/EtheaDev/SVGIconImageList/issues/229) - haven't tried iOS yet
{$ENDIF}

birbilis avatar May 24 '22 19:05 birbilis

forwarded the issue to Angus Johnson, author of Image32...

Thanks Carlo. I'm not doubting there's a problem, but I can't duplicate it, at least when just using Image32. I've attached a very simple demo FMX app that just uses Image32. And here are the Windows and Android screenshots:

fmx_svg_win

fmx_svg_android

fmx_svg_demo.zip

Edit: tidied up demo.

AngusJohnson avatar May 24 '22 23:05 AngusJohnson

I'm now wondering if this problem is due to a conflict between Image32 and Carlo's FMX.Image32SVG unit.

As you've observed above, Image32 swaps the red and blue channels (when the precompiler directive ANDROID is defined). However, I note Carlo's AlphaToColor32 function (line 72) calls TAlphaColorRec which also switches these color channels depending on endianness. IOWs, I suspect the blue and red channels are being swapped twice.

Edit: Unrelated to the above problem, I can see it's much better to manage red-blue color swaps based on endianness rather than platform, so I'll need to change this in Image32.

Edit2: Scrap all that. The red-blue issue is unrelated to endianness.

AngusJohnson avatar May 25 '22 08:05 AngusJohnson

Hi, if you don't see the issue in Image32 demos (didn't notice any in the version included in SVGIconImageList repo), but only happening in SVGIconImageList FMX demos (and in my app that uses that library), then it's definitely something added there or some difference in the files they have.

So, since there was another suspisious thing in that code, I think I found it.

My original fix showed ok: image

but not the FixedColor functionality of that demo, it was broken: image

so I went back to the code, first of all had checked the method you had mentioned and though it was being called a lot in the debugger (had breakpoint to confirm I had overriden it with my added changed unit in the demo project), it wasn't affecting the tint issue (whether I had my other fix added or not, it didn't affect something [apart maybe from the FixedColor I mention, didn't try that with it])

the correct (that solves both the tint and the FixedColor functionality) fix is here: image at the FMX.Image32SVG file of SVGIconImage repo

birbilis avatar May 25 '22 10:05 birbilis

to recap, ignore my originally proposed fix, the issue is in FMX.Image32SVG @carloBarazzetta please do this fix, tried on both Windows and Android (the R-B color channel reversal goes away and the FixedColor switch works fine too in both) - UPDATE: added pull request here: https://github.com/EtheaDev/SVGIconImageList/pull/231

Since I had observed the issue on OS-X, added OS-X too. However I have some issue with that demo to add OS-X target, fails to compile due to some file rights (can't write to the bin folder etc.). On my READCOM_App project OS-X target builds fine, so will check there too that the fix works on OS-X and let you know

Will also try on iOS Simulator soon (I hope) to see if the issue was ever there for that platform too

birbilis avatar May 25 '22 10:05 birbilis

since it's a major bug if you could release on GetIt a new version it would be great (just wait for me to check on iOS too)

birbilis avatar May 25 '22 10:05 birbilis

image

Yes, that may be useful in Image32 too.

AngusJohnson avatar May 25 '22 10:05 AngusJohnson

I confirmed this fix is fine for my app on Android, but on Mac OS-X it isn't doing the job (I tried both RGBA and BGRA there with no difference which is strange)

The reason might be that some other code that also does reversals and has only check for Android, not Mac OS-X (or vice-versa). In fact there's a chance there are too many reversals happening that could be avoided.

PAServer is quite slow to deploy to remote Mac, so not easy to try alternatives (takes some time)

Plus had seen some Image32 code that was getting the TPixelFormat from BitmapSurface, not sure what that was about, but maybe one could avoid conditional defines and just get the PixelFormat from the device canvas (though I'm not sure if that is accessible early in the app startup)? e.g. would Android on Intel platforms be using other pixel format that Android on ARM? (not that Delphi can target Android on Intel currently, but Windows is moving onto ARM too so we might have issues with that too in the future if MS doesn't handle such things under the hood)

Another thing is that I don't see MACOSX symbol at https://docwiki.embarcadero.com/RADStudio/Alexandria/en/Conditional_compilation_(Delphi) is it for FreePascal or something? I only see a newer one called OSX, but I guess best is to use older MACOS one (and just that if only targetting Delphi). Just in case I tried the fix with OSX symbol (my taget is Mac 64-bit [Intel CPU, an older iMac]), does the same

birbilis avatar May 25 '22 10:05 birbilis

Just remembered at UTF8StringToColor32 at Img32.SVG.Core.pas(1191) it was only reversing for Android, probably it needed to reverse for OS-X too so that the Copy Image32 to Bitmap other fix will then work. Fingers crossed, will try

birbilis avatar May 25 '22 11:05 birbilis

Indeed, it worked with this extra fix (this time at Image32's Img32.SVG.Core), aka to have near the end of UTF8StringToColor32 do color reversal for both Android and MacOS-X

an issue is that Image32 was using {$IFDEF ANDROID}...{$ENDIF} instead of {$IF Defined(Android)}...{$IFEND} (note the IFEND btw)

I used this but not sure if it compiles on FreePascal/Lazarus, plus see my question on what MACOSX symbol is (that Carlo uses in his code): image

birbilis avatar May 25 '22 11:05 birbilis

[DONE] will update the pull request if still open to have the fixes for both Android and OS-X or else make new one

birbilis avatar May 25 '22 11:05 birbilis

btw, regarding the use of IFEND, it's required by older compilers if one use $IF (newers accept $ENDIF from what I see). If compiler has issues it's mentioned that one can add {$IF CompilerVersion >= 24.0 } {$LEGACYIFEND ON} {$IFEND} https://docwiki.embarcadero.com/RADStudio/Alexandria/en/Legacy_IFEND_(Delphi) https://stackoverflow.com/a/38052789/903783

to be consistent with existing code in SVGIconImageList I'll use {$IFEND} at the fix I had done in FMX.Image32SVG too

birbilis avatar May 25 '22 11:05 birbilis

also note I tested on "Android on ARM" and "MacOS-X on Intel" targets

birbilis avatar May 25 '22 11:05 birbilis

an issue is that Image32 was using {$IFDEF ANDROID}...{$ENDIF} instead of {$IF Defined(Android)}...{$IFEND} (note the IFEND btw)

I used this but not sure if it compiles on FreePascal/Lazarus, plus see my question on what MACOSX symbol is (that Carlo uses in his code):

I've just fixed this but now I'm having problems uploading to Sourceforge.

AngusJohnson avatar May 25 '22 21:05 AngusJohnson

I'm still having problems with SourceForge and have decided to move the repository over to GitHub. (This was something I'd been considering for a while but with the issues I'm currently having with SF has prompted me to move to GitHub immediately. Besides, I have other repositories there.) Anyhow, Image32's updated code can be found here.

AngusJohnson avatar May 26 '22 07:05 AngusJohnson

will probably need to use that LEGACYIFEND code block I mentioned above to stop emitting warning for the use of the legacy IFEND (unless one doesn't care about older compilers that needed $IFEND to match $IF), else will get:

  • SVGIconImageList\Source\FMX.Image32SVG.pas(83,3): warning H2586: H2586 Legacy '$IFEND' directive found. Consider changing to '$ENDIF' or enable $LEGACYIFEND
  • SVGIconImageList\Source\FMX.Image32SVG.pas(177,155): warning H2586: H2586 Legacy '$IFEND' directive found. Consider changing to '$ENDIF' or enable $LEGACYIFEND

birbilis avatar May 26 '22 23:05 birbilis