| Author | 
                
                  Topic   | 
                  | 
               
              
                | 
                 Flashcqxg 
                    
                 
                
                131 Posts  | 
                
                  
                    
                      
                       Posted - Jan 23 2024 :  18:23:47
                        
                        
                      
  | 
                     
                    
                       Using TImageEnMIO to generate TIFF files in multithreading, but some of the generated images are blank without any text on them. What is the reason for this? The code is as follows:
 
procedure ProcessJob(const AJob: TJob);
var
  ABitmap: TIEBitmap;
  MViewIO: TImageEnMIO;
  X, Y: Integer;
  vTextW, vTextH, vOffSet: Integer;
  I, J, K: Integer;
  vText: string;
begin
  AddLog('Dealing#65306;' + IntToStr(AJob.FID));
  vOffSet := 15;
  MViewIO := TImageEnMIO.Create(nil);
  ABitmap := TIEBitmap.Create(3000, 2000, clWhite);
  ABitmap.Canvas.Lock;
  try
    try
      ABitmap.Canvas.Font.Color := clRed;
      ABitmap.Canvas.Font.Name := 'Times New Roman';
      ABitmap.Canvas.Font.Size := 50;
      vText := 'Hello Word';
      vTextW := ABitmap.Canvas.TextWidth(vText);
      ABitmap.Canvas.TextOut(Round((3000 - vTextW) / 2), 100, vText);
      ABitmap.Canvas.Font.Color := clRed;
      ABitmap.Canvas.Font.Name := 'Times New Roman';
      ABitmap.Canvas.Font.Size := 25;
      J := 0;
      K := 0;
      for I := 1 to 80 do
      begin
        X := 200 + J * 1000;
        Y := 300 + K * 50;
        ABitmap.Canvas.TextOut(X, Y, 'The ' + I.ToString + ' Testing');
        if (I mod 30) = 0 then
        begin
          Inc(J);
          K := 0;
        end
        else
          Inc(K);
      end;
      MViewIO.IEMBitmap.AppendImage(ABitmap);
      for I := 0 to MViewIO.ParamsCount - 1 do
      begin
        MViewIO.Params[I].TIFF_Compression := ioTIFF_JPEG;
        MViewIO.Params[I].TIFF_JPEGQuality := 80;
      end;
      MViewIO.SaveToFileTIFF(AJob.FSavePath + '\' + AJob.FID.ToString + '.TIFF');
    except
      on E: Exception do
      begin
        begin
          TThread.Synchronize(nil,
            procedure
            begin
              Form1.Memo1.Lines.Add(E.Message);
            end);
        end;
      end;
    end;
    AtomicIncrement(FSuccessed);
  finally
    ABitmap.Canvas.Unlock;
    ABitmap.Clear;
    ABitmap.Free;
    MViewIO.IEMBitmap.Clear;
    MViewIO.Free;
  end;
  AddLog('ok#65306;' + IntToStr(AJob.FID));
end;
 | 
                     
                   
                 | 
               
              
                | 
                 Flashcqxg 
                    
                 
                
                131 Posts  | 
                
                  
                    
                      
                       Posted - Jan 23 2024 :  18:37:53
                        
                        
                      
  | 
                     
                    
                      |  Furthermore, multiple tests have found that it does not occur every time, but rather randomly | 
                     
                    
                        | 
                     
                   
                 | 
               
              
                | 
                 xequte 
                      
                 
                
                39222 Posts  | 
                
                  
                    
                      
                       Posted - Jan 23 2024 :  19:14:21
                        
                        
                      
  | 
                     
                    
                       Hi
  You are using a TCanvas which converts the TIEBitmap to standard TBitmap storage.
  Try redoing the code using only TIECanvas to do to the text output, i.e. using ABitmap.IECanvas.DrawText (or AdvancedDrawText):
  http://www.imageen.com/help/TIECanvas.html
  Nigel  Xequte Software www.imageen.com
  | 
                     
                    
                        | 
                     
                   
                 | 
               
              
                | 
                 Flashcqxg 
                    
                 
                
                131 Posts  | 
                
                  
                    
                      
                       Posted - Jan 23 2024 :  19:29:12
                        
                        
                      
  | 
                     
                    
                       when i use  ABitmap.IECanvas.DrawText,the Error: Error creating GDI+ object (#21001) | 
                     
                    
                        | 
                     
                   
                 | 
               
              
                | 
                 xequte 
                      
                 
                
                39222 Posts  | 
                
                  
                    
                      
                       Posted - Jan 23 2024 :  22:30:11
                        
                        
                      
  | 
                     
                    
                       Please show me your code.
  Nigel  Xequte Software www.imageen.com
  | 
                     
                    
                        | 
                     
                   
                 | 
               
              
                | 
                 Flashcqxg 
                    
                 
                
                131 Posts  | 
                
                  
                 | 
               
              
                | 
                 xequte 
                      
                 
                
                39222 Posts  | 
                
                  
                    
                      
                       Posted - Jan 25 2024 :  20:11:50
                        
                        
                      
  | 
                     
                    
                       Hi
  Yes, that works fine for me. Even if I put the "Start Testing" button method in a 50x loop.
  Can you try adding a TImageEnView to the form (as this will prevent GDI+ from being loaded and unloaded everytime a TIEBitmap is created).
  What are the specs of the system and Windows version?
  Nigel  Xequte Software www.imageen.com
  | 
                     
                    
                        | 
                     
                   
                 | 
               
              
                | 
                 xequte 
                      
                 
                
                39222 Posts  | 
                
                  
                    
                      
                       Posted - Jan 25 2024 :  20:43:48
                        
                        
                      
  | 
                     
                    
                       Hi
  After some further testing I was able to reproduce a crash after about 40 iterations (40,000 images). As expected, the crash occurred due to loading/unloading of GDI+, so it was resolved by adding a TImageEnView to the form (or creating a TImageEnView at runtime and not freeing it until after processing).
 
 
  Nigel  Xequte Software www.imageen.com
  | 
                     
                    
                        | 
                     
                   
                 | 
               
              
                | 
                 Flashcqxg 
                    
                 
                
                131 Posts  | 
                
                  
                    
                      
                       Posted - Jan 25 2024 :  21:00:53
                        
                        
                      
  | 
                     
                    
                      |  Hello,i use windows 11. | 
                     
                    
                        | 
                     
                   
                 | 
               
              
                | 
                 Flashcqxg 
                    
                 
                
                131 Posts  | 
                
                  
                    
                      
                       Posted - Jan 25 2024 :  21:11:04
                        
                        
                      
  | 
                     
                    
                       Now I am using TImageEnIO to generate images and write text, but I still find that some images do not have text.
 
procedure ProcessJob(const AJob: TJob);
var
  IO: TImageEnIO;
  FS: TFileStream;
  X, Y: Integer;
  vTextW, vTextH, vOffSet: Integer;
  I, J, K: Integer;
  vText: string;
begin
  vOffSet := 15;
  IO := TImageEnIO.Create(nil);
  FS := TFileStream.Create(AJob.FSavePath + '\' + AJob.FID.ToString + '.TIFF', fmCreate);
  IO.IEBitmap.Create(3000, 2000, clWhite);
  try
    try
      try
        IO.IEBitmap.IECanvas.Font.Color := clRed;
        IO.IEBitmap.IECanvas.Font.Name := 'Times New Roman';
        IO.IEBitmap.IECanvas.Font.Size := 50;
        vText := 'Hello ImageEn';
        vTextW := IO.IEBitmap.IECanvas.TextWidth(vText);
        IO.IEBitmap.IECanvas.DrawText(vText, Round((3000 - vTextW) / 2), 100);
        IO.IEBitmap.IECanvas.Font.Color := clRed;
        IO.IEBitmap.IECanvas.Font.Name := 'Times New Roman';
        IO.IEBitmap.IECanvas.Font.Size := 25;
        J := 0;
        K := 0;
        for I := 1 to 80 do
        begin
          X := 200 + J * 1000;
          Y := 300 + K * 50;
          IO.IEBitmap.IECanvas.DrawText('The ' + I.ToString + ' Hello Word!', X, Y);
          if (I mod 30) = 0 then
          begin
            Inc(J);
            K := 0;
          end
          else
            Inc(K);
        end;
      finally
      end;
      IO.Params.TIFF_Compression := ioTIFF_JPEG;
      IO.Params.TIFF_JPEGQuality := 80;
      IO.SaveToStreamTIFF(FS);
    except
      on E: Exception do
      begin
        begin
          TThread.Synchronize(nil,
            procedure
            begin
              Form1.Memo1.Lines.Add('Error:' + E.Message);
            end);
        end;
      end;
    end;
    AtomicIncrement(FSuccessed);
  finally
    FS.Free;
    IO.Free;
  end;
end; | 
                     
                    
                        | 
                     
                   
                 | 
               
              
                | 
                 Flashcqxg 
                    
                 
                
                131 Posts  | 
                
                  
                    
                      
                       Posted - Jan 25 2024 :  21:49:58
                        
                        
                      
  | 
                     
                    
                       I tested using TImageEnView, generating 1000 images at a time. During the process of generating images, if the mouse drags the form, there will still be incomplete images (no text written in the images).
 
procedure ProcessJob(const AJob: TJob);
var
  // IO: TImageEnIO;
  ImageEnView1: TImageEnView;
  FS: TFileStream;
  X, Y: Integer;
  vTextW, vTextH, vOffSet: Integer;
  I, J, K: Integer;
  vText: string;
begin
  vOffSet := 15;
  // IO := TImageEnIO.Create(nil);
  ImageEnView1 := TImageEnView.Create(nil);
  ImageEnView1.Visible := False;
  FS := TFileStream.Create(AJob.FSavePath + '\' + AJob.FID.ToString + '.TIFF', fmCreate);
  ImageEnView1.IEBitmap.Create(3000, 2000, clWhite);
  try
    try
      ImageEnView1.IEBitmap.Canvas.Lock;
      try
        ImageEnView1.IEBitmap.Canvas.Font.Color := clRed;
        ImageEnView1.IEBitmap.Canvas.Font.Name := 'Times New Roman';
        ImageEnView1.IEBitmap.Canvas.Font.Size := 50;
        vText := 'Hello ImageEn';
        vTextW := ImageEnView1.IEBitmap.Canvas.TextWidth(vText);
        ImageEnView1.IEBitmap.Canvas.TextOut(Round((3000 - vTextW) / 2), 100, vText);
        ImageEnView1.IEBitmap.Canvas.Font.Color := clRed;
        ImageEnView1.IEBitmap.Canvas.Font.Name := 'Times New Roman';
        ImageEnView1.IEBitmap.Canvas.Font.Size := 25;
        J := 0;
        K := 0;
        for I := 1 to 80 do
        begin
          X := 200 + J * 1000;
          Y := 300 + K * 50;
          ImageEnView1.IEBitmap.Canvas.TextOut(X, Y, 'The ' + I.ToString + ' Hello Word!');
          if (I mod 30) = 0 then
          begin
            Inc(J);
            K := 0;
          end
          else
            Inc(K);
        end;
      finally
        ImageEnView1.IEBitmap.Canvas.Unlock;
      end;
      ImageEnView1.Update;
      ImageEnView1.IO.Params.TIFF_Compression := ioTIFF_JPEG;
      ImageEnView1.IO.Params.TIFF_JPEGQuality := 80;
      ImageEnView1.IO.SaveToStreamTIFF(FS);
    except
      on E: Exception do
      begin
        begin
          TThread.Synchronize(nil,
            procedure
            begin
              Form1.Memo1.Lines.Add('Error:' + E.Message);
            end);
        end;
      end;
    end;
    AtomicIncrement(FSuccessed);
  finally
    ImageEnView1.Blank;
    FS.Free;
    ImageEnView1.Free;
  end;
end; | 
                     
                    
                        | 
                     
                   
                 | 
               
              
                | 
                 xequte 
                      
                 
                
                39222 Posts  | 
                
                  
                 | 
               
              
                | 
                 Flashcqxg 
                    
                 
                
                131 Posts  | 
                
                  
                    
                      
                       Posted - Jan 26 2024 :  00:55:28
                        
                        
                      
  | 
                     
                    
                       When running, I dragged the form and encountered the following error
  Memo1 Error:Error creating GDI+ object (#21001) Error:Access violation at address 6ABA287C in module 'gdiplus.dll'. Read of address 00000028
  | 
                     
                    
                        | 
                     
                   
                 | 
               
              
                | 
                 Flashcqxg 
                    
                 
                
                131 Posts  | 
                
                  
                    
                      
                       Posted - Jan 26 2024 :  01:32:38
                        
                        
                      
  | 
                     
                    
                       This is my new testing program that only uses TImageEnIO.  Under multithreading, it is also unsafe as various exceptions may occur, such as errors or text that cannot be written on images.
 
 
 
 
   attach/Flashcqxg/202412624956_test.zip  97.64 KB | 
                     
                    
                        | 
                     
                   
                 | 
               
              
                | 
                 xequte 
                      
                 
                
                39222 Posts  | 
                
                  
                    
                      
                       Posted - Jan 30 2024 :  15:29:13
                        
                        
                      
  | 
                     
                    
                       Detailed reading of the Microsoft documentation implies that GDI+ is not fully thread-safe.
  See the Thread Synchronization at:
  https://learn.microsoft.com/en-gb/windows/win32/gdiplus/sec-gdiplus
  It seems that each call should be locked to avoid multiple thread access. Though that is not clear because the documentation states “when you access” the same object.
  We tested modifying our code so each thread loads its own library and initializes GDI+ but it did not help. The only way would be allow only a single thread at a time to access each method of GDI+. However that would mean you you lose the advantages of multi-threading.
  So, that means GDI+/TIECanvas is not your solution here. You could go back to the VCL TCanvas but it definitely has difficulty when used in threads (you should google for possible workarounds for that).
  The only other possibility is that if your text was generated outside of the thread and put into a TIEBitmap, then that TIEBitmap could be drawn onto another TIEBitmap in multi-threaded code.
 
  Nigel  Xequte Software www.imageen.com
  | 
                     
                    
                        | 
                     
                   
                 | 
               
              
                | 
                 Flashcqxg 
                    
                 
                
                131 Posts  | 
                
                  
                    
                      
                       Posted - Jan 30 2024 :  19:11:29
                        
                        
                      
  | 
                     
                    
                      | thanks. | 
                     
                    
                        | 
                     
                   
                 | 
               
              
                |   | 
                
                  Topic   | 
                  | 
               
             
           | 
         
       
     |