Page 1 of 1

DrawVectorImage(ImageID(img)) sometimes draws the wrong image

Posted: Thu Aug 28, 2025 4:15 pm
by dige
Unfortunately, the following code is not executable. It is part of a larger project.

Code: Select all

              txt = CreateBarCodeText(\ID)
              img = qrcodegen::CreateTextImage(txt)
              
              If img <> #PB_any And IsImage(img)
                MovePathCursor(PosX + 848, PosY)
                DrawVectorImage(ImageID(img))
                FreeImage(img)
              EndIf        
At this point:

1. A barcode image is created.
2. The image is drawn in the PDF.

This creates approximately 40 pages of business cards with QR codes for just under 500 people.
The problem arises that some business cards have another person's barcode printed on them.

When I save the image with SaveImage under the barcode ID (txt), everything is correct. But in the PDF, the drawn image is sometimes not the one that was just saved with SaveImage.

It seems that DrawVectorImage(ImageID(img)) sometimes does not draw the image with the ID in img, but one that has already been released with FreeImage.

After several hours of testing and troubleshooting, I have now discovered that the problem only occurs with the PB standard compiler, but not with the C backend.

So it must be a bug in the compiler.

@Fred: Please help! Please let me know what you need to find and fix this strange bug. You are also welcome to have the source code, etc.


Kind regrads

Dige

Re: DrawVectorImage(ImageID(img)) sometimes draws the wrong image

Posted: Thu Aug 28, 2025 4:38 pm
by Fred
It could be a race condition which doesn't happen with C because of optimisation. Do you use threads ?

Re: DrawVectorImage(ImageID(img)) sometimes draws the wrong image

Posted: Thu Aug 28, 2025 9:22 pm
by idle
is that the result of short circuit evaluation maybe?

Code: Select all

If (img <> #PB_any And IsImage(img))

Re: DrawVectorImage(ImageID(img)) sometimes draws the wrong image

Posted: Fri Aug 29, 2025 7:59 am
by dige
I did some more research and created executable code.
In the PDF, the image in the blue frame must contain the sequential number.
Starting on page 20, there are suddenly wrong images.
And unfortunately, this also happens with the C backend.

Code: Select all

Structure _USER
  ID.s 
  RegID.i
  Anrede.s    
  Titel.s
  Name.s
  Vorname.s
  Firma.s
  Funktion.s
  Strasse.s
  PLZ.s
  Ort.s
  EMail.s
  Telefon.s
  Kommentar.s
  Teilnahme.s
  ZusatzEvent.s
  Begleitung.s 
  Speichern.s
  HashID.s 
  CrC.s 
EndStructure



Procedure FindTheBug()
  
Protected Dim s.s(10)

pdffile.s = "C:\Temp\FindeTheBug.pdf"

Protected NewList U._USER(), UC._USER
Protected NewMap RplTxt.s()

  LoadFont(0, "Futura LT Pro Book", 100, #PB_Font_Bold)
  LoadFont(1, "Futura LT Pro Book", 30)

#VERSION = "2.38"
  #MAX_NAMEWIDTH = 830
  #MAX_FKT_WIDTH = 950



For i = 1 to 500
  AddElement(U())
  ;U()\Anrede = "Mr"
  ;U()\Firma = "Purebasic"
  U()\Vorname = "Jane"
  U()\Name = "Doe"
Next

  If StartVectorDrawing(PdfVectorOutput(pdffile, 2480, 3508))  
    
    ForEach U()
      
        pageNr + 1
        
        If IsImage(0)
          MovePathCursor(0, 0)
          DrawVectorImage(ImageID(0));
        EndIf
        
        VectorFont(FontID(1), 30)
        VectorSourceColor(RGBA(0, 0, 0, 255))

        txt.s = "Erstellt: " + FormatDate("%dd.%mm.%yyyy %hh:%ii", Date()) + " Uhr  |  " + #VERSION + "  |  Seite: " + Str(pageNr)
        MovePathCursor(VectorOutputWidth() - VectorTextWidth(txt) - 90, 5)
        DrawVectorText(txt)
        
        rowCount = 8 ; Textil
        PosY = 160
        
        
        For y = 1 To rowCount
          
          PosX = 190
          
          For x = 1 To 2
            
            UC = U()
            txt = ""
            
            With UC
              
              ;{ Name Vorname zweizeilig
              VectorFont(FontID(0), 70)
              VectorSourceColor(RGBA(Red(rgb_text), Green(rgb_text), Blue(rgb_text), 255))
              
               \Firma = Str(ListIndex(U()))
               \Name + " " + Str(ListIndex(U()))

              
              ; Vornamen maskieren und Doppelleerzeichen entfernen
              txt + ReplaceString(ReplaceString(\Vorname, "  ", " "), " ", "_") + " " + \Name
              txt = ReplaceString(txt, "  ", " ")
              txt2.s = ""
              
              w = VectorTextWidth(txt)
              
              If w > #MAX_NAMEWIDTH
                
                c = CountString(txt, Chr(32))
                
                If c > 0
                  
                  For i = 1 To c + 1
                    s(i) = StringField(txt, i, Chr(32))
                  Next
                  
                  If c = 1
                    txt  = s(c) 
                    txt2 = s(c+1)
                    
                  Else  
                    
                    txt = ""
                    
                    ; Bei sehr langen Nachnamen, muss der Vornamen mit hoch in die erste Zeile
                    If VectorTextWidth(s(c+1)) > 600
                      txt2 = s(c+1)
                      
                      For i = 1 To c
                        txt + s(i) + " "
                      Next

                    Else
                      txt2 = s(c) + " " + s(c+1)
                        
                      For i = 1 To c - 1
                        txt + s(i) + " "
                      Next
                    EndIf
                    
                    txt = Trim(txt)
                    
                  EndIf
                EndIf
                
                txt  = ReplaceString(txt, "_", " ")
                txt2 = ReplaceString(txt2, "_", " ")

                ; Wegen haufenweise Vornamen kann der Text zu lang sein,
                ; daher einfach vorletzten Namen entfernen
                ; Malte Hans Dixi Mustermann -> Malte Hans Mustermann
                
                w = VectorTextWidth(txt2)
                
                If w > #MAX_NAMEWIDTH
                  
                  c = CountString(txt2, Chr(32))
                
                  If c > 1
                  
                    For i = 1 To c + 1
                      s(i) = StringField(txt2, i, Chr(32))
                    Next
                    
                    ; WriteLog("Too long: " + txt2 + " -> Remove: " + s(c))
                    
                    s(c) = ""
                    txt2 = ""
                    
                    For i = 1 To c + 1
                      If s(i) <> ""
                        txt2 + s(i) + " "
                      EndIf
                    Next
                    
                    txt2 = Trim(txt2)
                  EndIf  
                EndIf

                
;                 Debug "Zeile 1 : " + txt
;                 Debug "Zeile 2 : " + txt2
              EndIf
              
              
;               AddPathBox(PosX, PosY, 1180, 400)
;               VectorSourceColor(RGBA(200, 200, 200, 255))
;               StrokePath(1)
;               VectorSourceColor(RGBA(Red(rgb_text), Green(rgb_text), Blue(rgb_text), 255))
              
              ; Hier auch nochmal, sonst nur bei überlängen wieder entfernt
              txt  = ReplaceString(txt, "_", " ")
              txt2 = ReplaceString(txt2, "_", " ")

              If 1
                ; Titel Vorname Name Zeile 1
                MovePathCursor(PosX, PosY)
                DrawVectorText(txt)
                Offset_Y + 100
                
                If txt2 <> ""
                  
                  ; Titel Vorname Name Zeile 2
                  MovePathCursor(PosX, PosY + Offset_Y)
                  DrawVectorText(txt2)
                  Offset_Y + 100
                EndIf
              EndIf
              
              
              ;}
              ;{ Funktion
              VectorFont(FontID(1), 40)
              
              txt = Trim(ReplaceString(\Funktion, ";", ","))
              ;WriteLog( txt + " | " + Str(VectorTextWidth(txt)))
              
              If VectorTextWidth(txt) > #MAX_FKT_WIDTH
                ForEach RplTxt()
                  If FindString(txt, MapKey(RplTxt()), 0, #PB_String_NoCase)
                    txt = ReplaceString(txt, MapKey(RplTxt()), RplTxt(), #PB_String_NoCase)
                  EndIf
                Next
              EndIf
              
              
              Repeat
                
                w = VectorTextWidth(txt)
                
                If w > #MAX_FKT_WIDTH
                  c = CountString(txt, Chr(32))
                  
                  If c > 0
                    txt = ReverseString(txt)
                    
                    c = FindString(txt, " ")
                    
                    txt = Mid(txt, c + 1)
                    
                    txt = ReverseString(txt)
                    
                  Else
                    
                    txt = Mid(txt, 1, Len(txt) - 1)
                  
                  EndIf
                  
                  w = VectorTextWidth(txt)
                  
                EndIf
                
              Until w <= #MAX_FKT_WIDTH
              
              ;txt = Remove_Chars_from_Right(txt)
              
              
              ;}
              
              ;{ Firma
              txt = Trim(ReplaceString(\Firma, ";", ","))
              
              If VectorTextWidth(txt) > #MAX_FKT_WIDTH
                ForEach RplTxt()
                  If FindString(txt, MapKey(RplTxt()), 0, #PB_String_NoCase)
                    txt = ReplaceString(txt, MapKey(RplTxt()), RplTxt(), #PB_String_NoCase)
                  EndIf
                Next
              EndIf

              
              Repeat
                w = VectorTextWidth(txt)
                
                If w > #MAX_FKT_WIDTH
                  c = CountString(txt, Chr(32))
                  
                  If c > 0
                    txt = ReverseString(txt)
                    
                    c = FindString(txt, " ")
                    
                    txt = Mid(txt, c + 1)
                    
                    txt = ReverseString(txt)
                    
                  Else
                    
                    txt = Mid(txt, 1, Len(txt) - 1)
                  
                  EndIf
                  
                  w = VectorTextWidth(txt)
                  
                EndIf
                
              Until w <= #MAX_FKT_WIDTH
            
              
              If Right(txt, 6) = ", Büro"
                txt = Mid(txt, 1, Len(txt) - 6)
              EndIf
              
              ;txt = Remove_Chars_from_Right(txt)
              
              If 1;styles & #TMPL_PREF_FIRMA
                MovePathCursor(PosX, PosY + Offset_Y)
                DrawVectorText(txt)
                Offset_Y + 70
              EndIf
            ;}

            
            ; b7a6f5517c684ba9348390ab100819ef -> #d7d3d0ed$
            If 1;styles & #TMPL_PREF_QRCODE
              ;txt = CreateBarCodeText(\ID)
              ;img = qrcodegen::CreateTextImage(txt)
              
              img = CreateImage(#PB_Any, 100, 100)
              
              If IsImage(img)
                
                If StartDrawing(ImageOutput(img))
                  Box(0, 0, OutputWidth(), OutputHeight(), #Blue)
                  Box(1, 1, OutputWidth()-2, OutputHeight()-2, #White)
                  DrawingMode(#PB_2DDrawing_Transparent)
                  DrawingFont(FontID(1))
                  DrawText(10, 10, Str(ListIndex(U())), #Black)
                  StopDrawing()
                
                Endif
                
                MovePathCursor(PosX + 848, PosY)
                DrawVectorImage(ImageID(img))
                
                MovePathCursor(PosX + 800, PosY + 140)
                DrawVectorText(txt)
                
                FreeImage(img)
              Else
              
              EndIf        
              
             
            EndIf
            
          EndWith
          
          PosX + 1180
          Offset_Y = 0
          
          If NextElement(U()) = 0
            ; Komplett abbrechen
            Break 3
          EndIf
        Next x
        
        PosY + 425

      Next y
        
      NewVectorPage()
      
      PreviousElement(U())
    Next
    
    StopVectorDrawing()
    
  EndIf
  
  EndProcedure
  
  FindTheBug()

Re: DrawVectorImage(ImageID(img)) sometimes draws the wrong image

Posted: Fri Aug 29, 2025 9:04 am
by idle
that's funky. If you don't free the img it appears to work. The pdf appears to be caching the img by handle
and if you free an image either PB or the OS will reuse the handle

Re: DrawVectorImage(ImageID(img)) sometimes draws the wrong image

Posted: Fri Aug 29, 2025 10:02 am
by dige
Hello idle, thank you very much for testing and clarifying the error issue.👍

Re: DrawVectorImage(ImageID(img)) sometimes draws the wrong image

Posted: Fri Aug 29, 2025 10:20 am
by macros
I performed the test too and here everything is in order independent of the compiler chosen. Can you maybe show a picture of what to expect?

Differences to your system may be: I am using Linux (Kubuntu 25.04), I recently changed my laptop, the CPU is fast with lots of RAM (7840HS 32GB RAM).

I even put FindTheBug() in a loop and generated 60 times and checked page 30 every time, looked ok every time.
(Okular, the KDE PDF Viewer autorefreshes on a file changes, making this easy)

Re: DrawVectorImage(ImageID(img)) sometimes draws the wrong image

Posted: Fri Aug 29, 2025 10:22 am
by miso
I cannot be sure, but I belive I had similar problems with entities that were freed. (Fast creation of bullets, and freeing them as they expire.) I use this with #pb_any, and I sometimes got a seemingly random crash while freeing an entity that should exist. I belive I did not make mistake with the ids, but to be sure, I will make a compact test on the weekend. (it was on Windows, I did not test other OS)

Re: DrawVectorImage(ImageID(img)) sometimes draws the wrong image

Posted: Fri Aug 29, 2025 11:05 am
by dige
macros wrote: Fri Aug 29, 2025 10:20 am I performed the test too and here everything is in order independent of the compiler chosen. Can you maybe show a picture of what to expect?
[..]
In the blue-framed images, should be visible the listindex number - the same as in the text next to it
The wrong images are marked red.

Image

Re: DrawVectorImage(ImageID(img)) sometimes draws the wrong image

Posted: Fri Aug 29, 2025 11:23 am
by macros
Ok thanks for the image. Now that I know exactly what to look for I performed some further tests.

On my Linux System everything is correct.

When I boot up my Win10 VM and let the code run there I observe a somewhat consistent error:
On Page 28 starting with Jane Doe 435 wrong images are shown. Index is then X-435. Depending on the run some or many images are still correct. Which ones seems random.

Re: DrawVectorImage(ImageID(img)) sometimes draws the wrong image

Posted: Fri Aug 29, 2025 12:35 pm
by Fred
You are right, there is an internal image caching based on DIB handle, but I guess it's not good enough as it can be reused overtime. I will see what can be done.

Re: DrawVectorImage(ImageID(img)) sometimes draws the wrong image

Posted: Fri Aug 29, 2025 2:33 pm
by dige
Okay, thanks Fred. I hope you can fix it.

Until then, I'll collect all the image IDs in a list for now and delete them later.

For now, I'm just really relieved that it's working. The incorrect QR codes on the business cards were really embarrassing for me :oops: .

Re: DrawVectorImage(ImageID(img)) sometimes draws the wrong image

Posted: Fri Aug 29, 2025 8:10 pm
by idle
Glad it works though not ideal.
I guess the pdf builds a glyph cache for pages or the whole document until its closed copying the image might fix it.