Delphi FMX loads images correctly to minimize memory usage (one of TBitmapSurface)

Delphi FMX loads images correctly to minimize memory usage (one of TBitmapSurface)

 

        Before National Day, I accidentally discovered that the App memory usage increased sharply, and it was discovered that it was caused by the loading of several 4K pictures (7680x4320 pixels) (TImage.Bitmap.LoadFromStream or TImage.Bitmap.LoadFromFile, when loading large pictures (>=6M), D10. 4, the memory is amazing, a total of 23M of 3 picture files, using the above syntax to eat close to 400M of memory), a group of friends who studied image processing reminded: the picture is in a compressed format, it must be decompressed when displayed, which takes up memory Of course it's big; all static pictures are equivalent to bmp bitmaps when displayed.

        I carefully read the source code of Delphi, and summarized the correct way to load pictures for everyone's reference:

procedure TfmxMain.FormShow(Sender: TObject);
begin
  {$IF DEFINED(IOS) or DEFINED(ANDROID) or DEFINED(MACOS)}
    //每个窗口必须有的,否则打不开新窗口:
    self.BorderStyle := TFmxFormBorderStyle.Sizeable;
  {$ENDIF}
  //创建主窗体并立即执行未来数据的异步下载:Main:

  if not Assigned(fmxMainUI) then
    fmxMainUI := TfmxMainUI.Create(Application);
  Application.MainForm := fmxMainUI;//fmxMainUI;

  FThread:=
  TThread.CreateAnonymousThread( //:创建一个单线程完成ATask
  procedure
    var
      LBitmapSurface1,LBitmapSurface2,LBitmapSurface3 :TBitmapSurface;
      LBitmapCodec :TBitmapCodecManager;
      LMaxSizeLimit: Cardinal;
      LLoadedBitmapSurface1,LLoadedBitmapSurface2,LLoadedBitmapSurface3 :Boolean;
      LmyFile1,LmyFile2,LmyFile3 :string;
  begin
    FEvent :=TEvent.Create;
    //sleep(4000);//:模拟临时区主界面显示多长时间:
      //:必须足够长顺便展示品牌,否则特别是MACOS反应不过来,
      //:因为fmxMainUI产生时动态生成大量图片菜单及远程下载数据需要时间:
    //if Image_grid01.Bitmap = nil then Image_grid01.Bitmap:=Image_grid01.MultiResBitmap.Items[0].Bitmap;
      // .\图标\牵引官网巨幕背景图4k_470x320Android_Icons_天蓝1.png
      //: 4320 x 7680 = 4k :设计时 + 美工1:1
    LBitmapSurface1 :=TBitmapSurface.Create;//:创建客制化位图界面
    LBitmapSurface2 :=TBitmapSurface.Create;
    LBitmapSurface3 :=TBitmapSurface.Create;
    LBitmapCodec :=TBitmapCodecManager.Create;
    {$IFDEF POSIX}
      {$IFDEF IOS}
            LMaxSizeLimit :=FDisplayMetrics.PhysicalScreenSize.cx;
            //:像素值:设备物理分辨率的短边值1080
            if LMaxSizeLimit<=1080*1 then //1K
            begin//:主流:
              LmyFile1 :=SJGY.GetADeploymentFile('Product001_1k.png');
              LmyFile2 :=SJGY.GetADeploymentFile('Product002_1k.png');
              LmyFile3 :=SJGY.GetADeploymentFile('Product003_1k.png');
            end;
          {$ELSE}
          {$IFDEF MACOS}
            LMaxSizeLimit :=FDisplayMetrics.PhysicalScreenSize.cx;//:像素值:像素值:设备物理分辨率的短边值1920
            //:即Screen.Size.cx;//dp像素密度值:1440;
            if LMaxSizeLimit<=1920*1 then //1K:我的MAC:1440
            begin//:主流:
              LmyFile1 :=SJGY.GetADeploymentFile('Product001_1k.png');
              LmyFile2 :=SJGY.GetADeploymentFile('Product002_1k.png');
              LmyFile3 :=SJGY.GetADeploymentFile('Product003_1k.png');
            end;
          {$ENDIF MACOS}
      {$ENDIF IOS}
      {$IF Defined(LINUX) or Defined(ANDROID)}
            LMaxSizeLimit :=FDisplayMetrics.PhysicalScreenSize.cx;
            //:像素值:设备物理分辨率的短边值1080
            if LMaxSizeLimit<=1080*1 then //1K
            begin//:主流:
              LmyFile1 :=SJGY.GetADeploymentFile('Product001_1k.png');
              LmyFile2 :=SJGY.GetADeploymentFile('Product002_1k.png');
              LmyFile3 :=SJGY.GetADeploymentFile('Product003_1k.png');
            end;
      {$ENDIF LINUX or ANDROID}  //:LINUX或ANDROID结束
    {$ENDIF POSIX} //:POSIX结束

    {$IFDEF MSWINDOWS}//:MSWINDOWS要独立写:
            LMaxSizeLimit :=FDisplayMetrics.PhysicalScreenSize.cx;
            //:像素值:设备物理分辨率的短边值1920
              //:MSWINDOWS下即Screen.Size.cx;//dp像素密度值:1920;
            if (LMaxSizeLimit<=1920*1) then //1K
            begin//:主流:
              LmyFile1 :=SJGY.GetADeploymentFile('Product001_1k.png');
              LmyFile2 :=SJGY.GetADeploymentFile('Product002_1k.png');
              LmyFile3 :=SJGY.GetADeploymentFile('Product003_1k.png');
            end;
            if (LMaxSizeLimit<=1920*2) and (LMaxSizeLimit>1920*1) then //2K
            begin//:已面世正在普及:
              LmyFile1 :=SJGY.GetADeploymentFile('Product001_2k.png');
              LmyFile2 :=SJGY.GetADeploymentFile('Product002_2k.png');
              LmyFile3 :=SJGY.GetADeploymentFile('Product003_2k.png');
            end;
            if (LMaxSizeLimit<=1920*4) and (LMaxSizeLimit>1920*2) then //4K
            begin//:截止2020年底实际中很少:
              LmyFile1 :=SJGY.GetADeploymentFile('Product001_4k.png');
              LmyFile2 :=SJGY.GetADeploymentFile('Product002_4k.png');
              LmyFile3 :=SJGY.GetADeploymentFile('Product003_4k.png');
            end;
    {$ENDIF MSWINDOWS}

    try
      LLoadedBitmapSurface1:=
        LBitmapCodec.LoadFromFile( LmyFile1,
          LBitmapSurface1, LMaxSizeLimit );//Ceil(LayoutTab.Width)
      LLoadedBitmapSurface2:=
        LBitmapCodec.LoadFromFile( LmyFile2,
          LBitmapSurface2, LMaxSizeLimit );//: LBitmapCodec :TBitmapCodecManager;
      LLoadedBitmapSurface3:=
        LBitmapCodec.LoadFromFile( LmyFile3,
          LBitmapSurface3, LMaxSizeLimit );//:像素值:以设备物理分辨率的短边值自适应适配
      while not (LLoadedBitmapSurface1 and LLoadedBitmapSurface2 and LLoadedBitmapSurface3) do sleep(0);

      //:宽屏设备才需要deployment图片并调出图片显示出来
        //:这样加载图片才是正确的最低限度占用内存的方式(23M的3个图片只占用1M左右内存):
        //:错误加载图片的方式:
          //Image01.Bitmap.LoadFromFile( SJGY.GetADeploymentFile('Product001_4k.png') );
          //Image02.Bitmap.LoadFromStream( TFileStream.Create(
            //SJGY.GetADeploymentFile('Product002_4k.png'),fmOpenRead) );
        //:共23M的3个图片文件,上面这三句造成控件加载Bitmap时吃了接近400M内存:
        //:另:在过去在长条度生成器实践中证实:Bitmap.LoadFromFile能加载的图片的最大像素尺寸:
          //:取决于内存大小:通常PC端8G内存大约共能加载不超过30张1M左右的图片;手机端4G内存<10张类似图片
      FEvent.SetEvent;

      TThread.Synchronize(nil,
      procedure
      begin
        if LLoadedBitmapSurface1 and LLoadedBitmapSurface2 and LLoadedBitmapSurface3 then
        begin
          Application.ProcessMessages;//:UI不阻塞
            fmxMainUI.Image01.Bitmap.Assign( LBitmapSurface1 );
            //:控件加载Bitmap到内存大小取决于BitmapSurface及其MaxSizeLimit像素尺寸:
          Application.ProcessMessages;
            fmxMainUI.Image02.Bitmap.Assign( LBitmapSurface2 );
          Application.ProcessMessages;
            fmxMainUI.Image03.Bitmap.Assign( LBitmapSurface3 );
            //fmxMainUI.myTitleLabel.Text:='测试最大尺寸限制:'+LMaxSizeLimit.ToString;
//===========其实就取决于位图及设定它显示所需的LMaxSizeLimit:=1920(关键),
//===========要想图片显示精度越大,图片就要设计像素尺寸越大,内存所需的分配空间就越大,就越耗内存
//===========下面不能设置而取的是位图自身默认的设计时像素尺寸所以大得惊人MaxSizeLimit:
            //fmxMainUI.Image01.Bitmap.LoadFromFile(LmyFile1);
          Application.ProcessMessages;
        end;
        Application.ProcessMessages;
        if not Application.HandleMessage then
          fmxMainUI.Show;
        if FEvent<>nil then
        begin
          FEvent.DisposeOf; if FEvent<>nil then FEvent:=nil;
        end;

        fmxMain.Close;

      end);
    finally
      LBitmapSurface1.DisPoseOf;//:释放客制化位图界面
      LBitmapSurface2.DisPoseOf;
      LBitmapSurface3.DisPoseOf;
    end;
  end );//.Start;
  FThread.Start;

end;

        //: When the artist is designing a picture,
        //: can center the content to be expressed in the core of the picture, and use the background image or background color to express the surroundings,
        //: use this to carry out responsive picture design,
        //: the picture can be Designed for 4k (PNG24) output, which meets the pixel size accuracy and reduces the number of memory bytes,
        //:4k: 1080*4=4320,1920*4=7680,
        //: The core content of the art design picture centered The critical height needs to be controlled:
        //: =TImage.Height=432, 768(: the critical width, but the actual width direction can be more design content,
        //: it does not matter if the part beyond the ClientWidth of the form is automatically covered)
        //: Second, the picture is automatically TAlignLayout.Fit; WrapMode:=TImageWrapMode.Center layout in the container

  {if LayoutTab.Visible=true then
  begin //: FormCreate defines the visibility of LayoutTab and whether the picture is loaded:
    //: widescreen devices only need to
    deploy the picture and call up the picture to display: if self.ClientWidth <= 768 then
    begin
      LayoutTab. Width:=self.ClientWidth;
      LayoutTab.Height:= //0.5625: aspect ratio, device screen scaling ratio ScreenScale;
        (FDisplayMetrics.RawScreenSize.cy * LayoutTab.Width)
        /FDisplayMetrics.RawScreenSize.cx;
    end;
  end; // }

 

 

Related blog posts on this blog:

      1. "Delphi XE About the ContentProvider of the Four Android Components: Case Delphi XE's Efficiency of Loading Android Phone Pictures"

      https://blog.csdn.net/pulledup/article/details/105642380

      2. "Delphi code and ideas for handling high-speed file upload and download"

      https://blog.csdn.net/pulledup/article/details/108660481

      3. " Delphi FMX loads images correctly to minimize memory usage (two TImageList) "

      https://blog.csdn.net/pulledup/article/details/108979086

If you like it, just click like and favorite below, so that you can watch the next sharing:

 

Guess you like

Origin blog.csdn.net/pulledup/article/details/108935897