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

Post bugreports for the Windows version here
dige
Addict
Addict
Posts: 1404
Joined: Wed Apr 30, 2003 8:15 am
Location: Germany
Contact:

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

Post 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
"Daddy, I'll run faster, then it is not so far..."
Fred
Administrator
Administrator
Posts: 18199
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

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

Post by Fred »

It could be a race condition which doesn't happen with C because of optimisation. Do you use threads ?
User avatar
idle
Always Here
Always Here
Posts: 5887
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

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

Post by idle »

is that the result of short circuit evaluation maybe?

Code: Select all

If (img <> #PB_any And IsImage(img))
dige
Addict
Addict
Posts: 1404
Joined: Wed Apr 30, 2003 8:15 am
Location: Germany
Contact:

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

Post 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()
"Daddy, I'll run faster, then it is not so far..."
User avatar
idle
Always Here
Always Here
Posts: 5887
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

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

Post 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
dige
Addict
Addict
Posts: 1404
Joined: Wed Apr 30, 2003 8:15 am
Location: Germany
Contact:

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

Post by dige »

Hello idle, thank you very much for testing and clarifying the error issue.👍
"Daddy, I'll run faster, then it is not so far..."
User avatar
macros
User
User
Posts: 92
Joined: Wed Mar 15, 2006 1:47 pm
Location: Munich

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

Post 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)
miso
Enthusiast
Enthusiast
Posts: 466
Joined: Sat Oct 21, 2023 4:06 pm
Location: Hungary

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

Post 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)
dige
Addict
Addict
Posts: 1404
Joined: Wed Apr 30, 2003 8:15 am
Location: Germany
Contact:

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

Post 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
"Daddy, I'll run faster, then it is not so far..."
User avatar
macros
User
User
Posts: 92
Joined: Wed Mar 15, 2006 1:47 pm
Location: Munich

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

Post 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.
Fred
Administrator
Administrator
Posts: 18199
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

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

Post 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.
dige
Addict
Addict
Posts: 1404
Joined: Wed Apr 30, 2003 8:15 am
Location: Germany
Contact:

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

Post 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: .
"Daddy, I'll run faster, then it is not so far..."
User avatar
idle
Always Here
Always Here
Posts: 5887
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

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

Post 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.
Post Reply