Zuschneidebereich hat im neuen Bitmap einen x- und y-Offset, aber nur, wenn Original skaliert worden ist

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 7 Antworten in diesem Thema. Der letzte Beitrag () ist von RodFromGermany.

    Zuschneidebereich hat im neuen Bitmap einen x- und y-Offset, aber nur, wenn Original skaliert worden ist

    Hi,
    es tritt ein komisches Phänomen auf.
    Mit meinem Kantendetektionsprogramm kann ich, wie einige wissen, das Innere das GraphicsPaths auf ein neues Bild übertragen. Dies geschieht wie folgt:

    Spoiler anzeigen

    VB.NET-Quellcode

    1. [vbnet]
    2. Imports System.Drawing.Drawing2D
    3. Imports Microsoft.WindowsAPICodePack.Dialogs
    4. Public NotInheritable Class AllesGrafische
    5. Public Shared Sub Paint_the_Rectangle(ByVal g As Graphics, ByVal recta As Rectangle)
    6. If g IsNot Nothing Then
    7. g.SmoothingMode = SmoothingMode.AntiAlias
    8. g.CompositingQuality = CompositingQuality.HighQuality
    9. g.PixelOffsetMode = PixelOffsetMode.HighQuality
    10. g.InterpolationMode = InterpolationMode.HighQualityBilinear
    11. Using Pen_Hellblau As Pen = New Pen(Color.FromArgb(0, 200, 255), 1.0F)
    12. g.DrawRectangle(Pen_Hellblau, recta)
    13. End Using
    14. End If
    15. End Sub
    16. Public Shared Sub Draw_Curve(ByVal g As Graphics, ByVal theList As List(Of Point))
    17. If theList IsNot Nothing AndAlso theList.Count > 0 AndAlso g IsNot Nothing Then
    18. g.SmoothingMode = SmoothingMode.AntiAlias
    19. g.CompositingQuality = CompositingQuality.HighQuality
    20. g.PixelOffsetMode = PixelOffsetMode.HighQuality
    21. g.InterpolationMode = InterpolationMode.HighQualityBilinear
    22. Dim theList_neu As New List(Of Point)
    23. Using gp As New GraphicsPath
    24. For i As Integer = 1 To theList.Count - 1 Step 1
    25. Dim a As Integer = theList(i).X
    26. Dim b As Integer = theList(i).Y
    27. Dim c As Integer = theList(i - 1).X
    28. Dim d As Integer = theList(i - 1).Y
    29. Dim Entfernungsbetrag As Double = Math.Sqrt(Math.Pow(a, 2) + Math.Pow(b, 2) + Math.Pow(c, 2) + Math.Pow(d, 2) - 2 * a * c - 2 * b * d)
    30. If Entfernungsbetrag < Form1.erlaubte_Entfernung Then
    31. theList_neu.Add(theList(i))
    32. End If
    33. Next
    34. If theList_neu.Count = 0 Then Return
    35. gp.AddLines(theList_neu.ToArray())
    36. Using Pen_hellrosa As Pen = New Pen(Color.FromArgb(255, 64, 239), 1.0F)
    37. g.DrawPath(Pen_hellrosa, gp)
    38. End Using
    39. If Form1.ClosePath Then
    40. gp.CloseFigure()
    41. End If
    42. If Form1.CheckBox1.Checked Then
    43. Dim Speicherpfad As String
    44. Using SFD1 As New CommonSaveFileDialog
    45. SFD1.Title = "Wo soll das Bild gespeichert werden?"
    46. SFD1.Filters.Add(New CommonFileDialogFilter("PNG", ".png"))
    47. If System.IO.Directory.Exists("C:\Users\...\source\repos\VB.NET\Get mouse position and draw rectangle on screen") Then
    48. SFD1.InitialDirectory = "C:\Users\...\source\repos\VB.NET\Get mouse position and draw rectangle on screen"
    49. Else
    50. SFD1.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop)
    51. End If
    52. If SFD1.ShowDialog = CommonFileDialogResult.Ok Then
    53. Speicherpfad = SFD1.FileName & ".png"
    54. Else
    55. Return
    56. End If
    57. End Using
    58. Using bmpSource As Bitmap = New Bitmap(Form1.Pfad_Bild)
    59. Dim rectCutout As RectangleF = gp.GetBounds()
    60. Using m As Matrix = New Matrix()
    61. m.Translate(-rectCutout.Left, -rectCutout.Top)
    62. gp.Transform(m)
    63. End Using
    64. Using bmpCutout As Bitmap = New Bitmap(CInt(Math.Round(rectCutout.Width, 0)), CInt(Math.Round(rectCutout.Height, 0)))
    65. Using graphicsCutout As Graphics = Graphics.FromImage(bmpCutout)
    66. graphicsCutout.Clip = New Region(gp)
    67. graphicsCutout.DrawImage(bmpSource, -rectCutout.Left, -rectCutout.Top)
    68. bmpCutout.Save(Speicherpfad, Imaging.ImageFormat.Png)
    69. Form1.CheckBox1.Checked = False
    70. End Using
    71. End Using
    72. End Using
    73. End If
    74. End Using
    75. End If
    76. End Sub
    77. End Class
    [/vbnet]

    Das klappt auch immer super – außer, wenn ich mit GIMP das Original skaliere (Seitenverhältnis bleibt aber, nur die Maße werden geändert). Dann ist der Bereich verschoben. Nach links und nach oben. Siehe Anhang. In Zeile 68 habe ich geschaut, was in rectCutout drin steht. Alles in Ordnung.

    Hat das etwas mit GIMP zu tun? Die dots per inch sind dieselben (72). Die Kompressionsqualität des JPEGs auch (100%).
    Bilder
    • 20210122_175942 skaliert.jpg

      316,09 kB, 675×900, 52 mal angesehen
    • Programmoberfläche, bereit zum Speichern - Kopie.png

      425,58 kB, 754×989, 58 mal angesehen
    • ausgeschnitten.png

      72,01 kB, 209×450, 64 mal angesehen
    @nafets Selber Fehler ...

    Edit: ich habe gerade festgestellt: Wenn ich ein Bild größer skaliere, ist das Ergebnis komplett schwarz.

    Edit 2: Das Merkwürdige ist: Ich sage ja nicht: Das Bild, auf dem gezeichnet wird, ist größer als das Bild, das gespeichert wird. Dann wäre es logisch, dass der Pfad nicht an derselben Postition ist. Sondern es geht darum, dass das geladene einfach nur kleiner ist.

    Edit 3: wenn ich mit Word skaliere, habe ich dasselbe Problem. Sch****

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Bartosz“ ()

    Bartosz schrieb:

    Wenn ich ein Bild größer skaliere
    Wie skalierst Du?
    Du musst natürlich die Mauskoordinaten in die skalierten Bild-Pixel-Koordinaten umrechnen: Nimm den Dreisatz.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany Ich habe mir ein Bild vom Smartphone auf den PC kopiert. Da dieses 16 MP hat, musste ich es mit GIMP skalieren, damit es auf meinen 1920x1080 Bildschirm passt (und ich überhaupt alles drauf hab). Das Programm selbst skaliert nicht. Also aus Sicht meines Programms ist das ein normales Bild, wo ich ein Rechteck ziehe, ein graphicsPath gemalt wird und dieses Rechteck 1:1 auf ein neues Bild übertragen wird.
    Man sieht auch, dass der Shape die Form des Taschenrechners annimmt, aber versetzt ist. Und das wundert micht so.
    Ich habe den Fehler gefunden. Ich habe extra geschaut, wie viele dpi das Handyfoto hat und diese Zahl auch bei GIMP eingestellt. Da muss irgendetwas schiefgelaufen sein. Jedenfalls verwende ich nun

    VB.NET-Quellcode

    1. Using bmpCutout As Bitmap = New Bitmap(CInt(Math.Round(rectCutout.Width, 0)), CInt(Math.Round(rectCutout.Height, 0)))
    2. bmpCutout.SetResolution(Original.HorizontalResolution, Original.VerticalResolution)

    und damit läuft es wieder.
    Mir war irgendwie klar, dass es so eine Geschichte sein muss, bei einem x- und y-Offset, aber mit den DPI war ich mir sicher.
    :cursing: Oder anders formuliert: Visual Basic macht, wenn eine neue Bitmapinstanz erzeugt wird, dieses Bitmap auf 96 dpi. Wenn ein Foto nur 72 dpi hat, dann ist das Mist. Daher war der Versatz weiter links und weiter oben.

    Bartosz schrieb:

    Also aus Sicht meines Programms ist das ein normales Bild, wo ich ein Rechteck ziehe
    dessen Mouse-Koordinaten von (0,0) bis (1920,1080) gehen, Du erwartest Mauskoordinaten von ()0,0) bis (1024,640) oder so.
    Gib Deine Mauskoordinaten in der Konsole aus.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!