Dokumentation zu HIDPI-Picture

Die Dokumentation zu Picture zeigt 2 Constructors und nennt die Property ‘Graphics’. Leider ist aber die Graphics-Property bei einen HIDPI-Picture immer Nil, d.h. nichts anderes, als dass ich eine einzelne Bitmap nur bearbeiten kann, wenn ich sie in ein ‘normales’ Picture kopiere (d.h. in 3 Versionen) und die nachher wieder in ein HIDPI-Picture ‘verwandle’.
Dazu muss ich aber z. B. bei 2 Monitoren mit verschiedener Auflösung je nach Aufgabe den scalefactor kennen, sobald ich ein Picture grössenabhängig verändern will. Das kann ziemlich kompliziert sein (jedenfalls finde ich keine Möglichkeit, den Screen, auf dem ich mich befinde, abzufragen).
Wie auch immer: Es wäre schon schön, diese Zusammenhänge in der Doku zu finden. Nimmt man den ‘Picture’-Eintrag wörtlich, dann ist er nicht nur irreführend, sondern falsch.

Die Dokumentation zu HiDPI ist relativ dürftig oder verwirrend. In den meisten Fällen kann HiDPI ignoriert werden. Wenn mehrere Pictures verarbeitet werden sollen, dann habe ich hier ein Beispiel - ich glaube adaptiert von Greg:

Protected Function MakeDarker(original as Picture, amount as double) as Picture
  Dim n As Integer=original.ImageCount
  If n=0 Then
    Return MakeDarkerInner(original, amount)
  Else
    Dim pp() As Picture
    n=n-1
    for i as integer=0 to n
      pp.AddRow MakeDarkerInner(original.ImageAt(i), amount)
    Next
    Return new Picture(original.Width, original.Height, pp)
  End If
End Function


Private Function MakeDarkerInner(OriginalPicture as Picture, theAmount as Double) as Picture
  'change the value (lighter or darker) for the Original Picture
  
  Dim OriginalHeight As Integer = OriginalPicture.height
  Dim OriginalWidth As Integer = OriginalPicture.width
  
  Dim OriginalRGBS As RGBSurface = OriginalPicture.RGBSurface
  
  //If you want, you can use the new constructor (without mask object)
  dim ResultPicture as new Picture(OriginalPicture.Width, OriginalPicture.Height, 32)
  'Dim ResultPicture As New Picture(OriginalPicture.Width, OriginalPicture.Height)
  dim ResultRGBS as RGBSurface = ResultPicture.RGBSurface
  
  for currentX as Integer = 0 to OriginalWidth
    for currentY as Integer = 0 to OriginalHeight
      dim theColor as Color = OriginalRGBS.Pixel(currentX, currentY)
      ResultRGBS.Pixel(currentX, CurrentY) = HSV(theColor.Hue, theColor.Saturation, theColor.Value * theAmount)
    next
  next
  If OriginalPicture.Mask=Nil Then
    //if you use the ,32 constructor set the mask
    //ResultPicture.Mask=OriginalPicture.CopyMask
    //otherwise apply it
    ResultPicture.ApplyMask OriginalPicture.CopyMask
  Else
    //if you use the ,32 constructor set the mask ResultPicture.Mask = OriginalPicture.mask
    //otherwise apply it
    ResultPicture.ApplyMask OriginalPicture.Mask
  End If
  Return ResultPicture
End Function

Danke.
An sich habe ich nach langen Versuchen schon verstanden, wie es funktioniert. Ich arbeite für eine sehr spezielle Edition an einem eigenen Schriftsystem mit eigenen Glyphen und da ist das HIDPI-Format an sich sehr nützlich.
Was mich stört, ist einfach die in diesem Fall ziemlich schlampige Dokumentation. Tatsächlich wäre es ja durchaus möglich, die Graphic-Klasse auch für HIDPI-Pictures zu öffnen. Irgendwo hat es ja ein Beispiel, wie man das Ding auseinandernehmen und neu zusammensetzen kann - ich finde es allerdings gerade auch (!) wieder nicht. Verstanden habe ich das Beispiel auch erst, nachdem ich selbst mühsam begriffen hatte, warum es geht.) Xojo ist angetreten, um auch für Nicht-Informatiker verwendbar zu sein und da sollte die Doku einigermassen konsistent sein.

Was genau möchtest du denn mit dem HiDPI-Picture machen?

Es gibt hier eine Funktion BitmapForCaching:
http://documentation.xojo.com/api/deprecated/window.html#window-bitmapforcaching

Diese liefert dir ein HiDPI-Bild bei dem du dann ganz normal das Graphics-Objekt verwenden kannst.

Danke für die Antwort, aber wenn ich den Code von Window.BitmapForCaching recht verstehe, dann ändert er einfach das Scaling. Ich benötige 3 Bilder nach dem folgenden Modus:

Var p() as Picture
for i as Integer = 0 to 2
p.add new Picture(w * i, h * i)
next
HIDPIPict = return new picture(p(0).width, p(0).heigth, p)

Hier hinein muss ich ein Zeichen mit 3 FontSizes schreiben (z.B. “A”), um ein Picture mit “A” zu erhalten, das den Buchstaben in allen Auflösungen sauber wiedergibt. Aber nochmals: Mir ist die Lösung klar, Ich habe ganz einfach die objektiv unzureichende Dokumentation moniert. Sie suggeriert, dass ein Picture (auch ein HDPI-Picture = 2. Constructor) eine Graphics-Property hat. Zusätzlich nennt sie die Bitmaps ‘immutable’, was eben heisst, dass sie nicht veränderbar sind (was wiederum eine Graphics-Property bei ihnen eigentlich obsolet macht). Wer logisch denkt, muss zum Schluss kommen, dass die Graphics-Property des HIDPI-Bildes nicht NIL sein darf (also ein Fehler in Xojo). Das Herumturnen mit ImageSet und Images in der Terminologie ist dabei wenig hilfreich. Am Ende hat man im Programmtext eben einfach Pictures.

Mein Vorschlag wäre: Die HIDPI-Pictures separat ohne die nicht vorhandenen Properties zu dokumentieren und dort ein Beispiel zu geben, wie man das Ding wieder in mutable-pictures auflöst, an denen die Eigenschaften ändert und sie dann wieder in ein HIDPI-Bild einbaut. (Das lässt sich übrigens mit einer eigenen Klasse, die zunächst 3 skalierte pictures enthält zusammen mit einem set/get-System auch generell erledigen - ob es immer besonders effizient ist, sei dahingestelt.)

Ich verstehe nicht warum alle 3 Bilder einzeln behandelt werden müssen?
Dieser Code in einem Canvas.Paint event sollte den Buchstaben “A” in einem Picture immer in Hi-DPI darstellen:

Var p As Picture = Self.BitmapForCaching(50, 50)
p.Graphics.DrawText "A", 25, 25

g.DrawPicture p, 0, 0

Ich kann das im Moment nur leider nicht testen, da ich hier gerade keinen HiDPI-Monitor habe.

Wenn ich ein kleines Picture mit einem “A” FontSize 12 in 72 dpi habe, dann bringt das keine saubere Schrift, wenn es auf 144 dpi skaliert, aber auf die Grösse des 72 dpi-Bildes aufgeblasen wird - auch der Weg von 216 abwärts geht nicht gut. Es geht um ein Schriftsystem, das gedreht werden kann und das sich auch im Web verwenden lässt (Ich benötige für meine Anwendung eine Kontrolle der Schrift, die über das hinausgeht, was ‘man’ so braucht.)
Bei kleinen Bildern ist die Skalierung häufig absolut unzureichend, weil man einfach einen amorphen Pixelhaufen erhält.
BTW: Um die Sache benutzbar zu machen, muss ich die Pictures in eine Datenbank kriegen.

Und wenn du das probierst?

Var p As Picture = Self.BitmapForCaching(50, 50)

p.Grahpics.TextSize = 12.0 * p.Graphics.ScaleX
p.Graphics.DrawText "A", 25, 25

g.DrawPicture p, 0, 0

Müssen die Bilder im Programm dargestellt werden oder nur in einer Datenbank für die Ausgabe?
Speichern in der Datenbank einfach als Base64 String oder so.

Genau deswegen ist die Dokumentation so vermurkst.

Wenn Du einfach nur Text malen willst, dann ist folgender Code richtig:

'draw text
mutableBubble.Graphics.FontUnit = FontUnits.Point
mutableBubble.Graphics.FontName = getAppearanceFont(False)
mutableBubble.Graphics.FontSize = FontSize * ScaleFactor
mutableBubble.Graphics.Bold = doBold
mutableBubble.Graphics.DrawingColor = rgb(200, 200, 200)
mutableBubble.Graphics.DrawText(ButtonText, (xOffset + 1) * ScaleFactor, (ButtonHeight/2 - FontSize/2 + bubble.Graphics.TextHeight + 1) * ScaleFactor)
mutableBubble.Graphics.DrawingColor = TextColor
mutableBubble.Graphics.DrawText(ButtonText, xOffset * ScaleFactor, (ButtonHeight/2 - FontSize/2 + bubble.Graphics.TextHeight) * ScaleFactor)

FontUnits.Point setzen und dann den Text malen. Nur beim x und y wird der Scale-Factor benötigt.

Ich bin für die Hilfe dankbar, aber ich muss in meinem Fall einfach Pictures haben. Die kurze Erläuterung:
Aus den Glyphen(d.h.Pictures) wird ein Text in einem Picture erzeugt. Dazu kommt ein 2. Picture, das an den Positionen der Glyphe einen farbenes Rechteck in der Grösse der Glyphe setzt, dessen Farbe einen Index abbildet, der über den Cursor erfragt werden kann. Dazu muss ich analog noch eine Blockmarkierung in einem 3. Picture ermöglichen, denn der Text muss kopierbar sein. Das Ganze (d.h. die Gylphen) muss ich max. 3x durchstreichen und wenn nötig doppelt und einfach unterstreichen können (mit Farbzuweisung). Dann muss das Ganze auch drehbar sein, weil Autoren hin- und wieder ihre Manuskripte auch schräg oder am Rand korrigieren, resp. ergänzen.

Es geht um etwas, das man in der Edition diplomatische Wiedergabe (Transkription eines Faksimile) von Handschriften nennt. Und weil man heute einer Client-Server-Anwendung reserviert gegenübersteht (Sicherheit - was ziemlich absurd ist) und überhaupt und generell nur mit einem Browser werkeln will, muss das Ganze auch browserfähig sein. Sowas benötigen auf Seite der Entwicklung vielleicht 50-100 Editoren weltweit (aber nur wenn man grosszügig rechnet) und ich habe deswegen keine Mühe damit, dass man solche Probleme idR nicht hat - aber ich habe sie eben.

Dann brauchst Du die erste Variante, die ich gepostet habe.

Das heißt aber schon, dass du in dem Fall für die 3 verschiedenen Pictures auch 3 verschiedene HiDPI Pictures erzeugst (und nicht die 3 unterschiedlichen Darstellungsvarianten versuchst in einem HiDPI Picture zu machen)?

Natürlich. Das IndexPicture bleibt im Speicher und wird nicht dargestellt (der Wert eines Pixels wird abgefragt und in eine UInt32 verwandelt, die in einer ValentinaTabelle den RecId gibt). Das BlockPict ist transparent und der Block wird mit semitranparenten Graupicts markiert.
Ich habe mir eine Klasse clHIDPIPicture gebaut, die einen PictureArray(2) enthält, auf den ich die Graphics nach dem folgenden Muster ausführe:

Methoden:
Sub Graphics_DrawLine(X1_ As Double, Y1_ As Double, X2_ As Double, Y2_ As Double) for i as Integer = 1 to 3
BitMapsArr(i-1).Graphics.DrawLine(X1_*i, Y1_*i, X2_*i, Y2_*i) next
End Sub

Eigenschaften mittels Computed Property
set auf alle 3 Bilder
get idR nur vom 1. Bild (alle idR gleich)

Ich habe das noch nicht getestet, müsste aber gehen.

Was ich aber weiss und auch getestet habe ist, dass die Textausgabe in Form dieser HIDPI-Bilder gut funktioniert. Da der Benutzer nur mit fertigen Bildern der Seite operiert, sollte das auch keine Speed-Probleme geben (die fertigen Seiten kommen auch in die Datenbank!)