Drucken eines PNG Logo auf einen "Kassenbon"

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
Benutzeravatar
Beach
Lazarusforum e. V.
Beiträge: 60
Registriert: Di 2. Nov 2021, 22:41
OS, Lazarus, FPC: Lazarus 3.0RC1 (rev lazarus_3_0_RC1-10-gfe49fef4fc) FPC 3.2.2 x86_64-win64-win32
CPU-Target: 64Bit
Wohnort: Hunsrück

Drucken eines PNG Logo auf einen "Kassenbon"

Beitrag von Beach »

Servus.
Ich habe ein Programm welches mir einen Bestellbon erstellt und dann auf einem Kassenbondrucker ausdruckt.
Das klappt aktuell auch alles soweit wie es soll. Der Text des Bon wird in einem TMemo zusammengestellt und dann wird der Inhalt des Memo ausgedruckt. Nun möchte ich aber am Anfang des Bons ein Logo (liegt als PNG mit 5000x2541 px vor) einfügen und dann erst den Text.
Habe mit der Suche auch ein paar Themen gefunden, (z.B. https://www.delphipraxis.net/172435-png ... ken-2.html ) aber trotzdem will das ganze noch nicht so wie ich will.
Das PNG wird zur Kontrolle in ein TImage geladen. Dann das TImage einem TPortableNetworkGraphic zugewiesen. Und dann soll das gedruckt werden.

Das Logo erscheint im TImage wie geplant, aber es wird einfach nichts gedruckt.
Ist mein PNG einfach zu groß und es wird nicht skaliert? Oder stehe ich einfach auf einem Knoten?
Bitte bringt etwas Licht in meine Dunkelheit.

Code: Alles auswählen

procedure TForm1.panelPrintMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: integer);                                 // Drucken
const
  LEFTMARGIN = 0;
var
  i, j, YPos, LineHeight, VerticalMargin: integer;
  zeile, error: string;
  b: TPortableNetworkGraphic;
begin
  if config.printed then exit;
  if config.main_dish = 0 then exit;

  changePanel(panelPrint);
  Printer.Copies := 2;
  error := 'Kein Fehler';
  try
    Form1.Image1.Picture.LoadFromFile(ExtractFilePath(ParamStr(0)) + 'logo_ffw.png');

  except
    on E: EInOutError do
      error := 'File handling error occurred. Details: ' + E.ClassName + '/' + E.Message;
  end;
  //Form1.Image1.Transparent:= false;
  try
    b := TPortableNetworkGraphic.Create;
    //  b.Transparent:= false;
    b.Canvas.Brush.Color := clBlue;
    b.Canvas.Rectangle(0, 0, round(Image1.Picture.Graphic.Width / 33),
      round(Image1.Picture.Graphic.Height / 33));
    b.Assign(Image1.Picture.Graphic);
  except
    error := 'Fehler beim Bilderzeugen';
  end;
  with Printer do
  try
    BeginDoc;
    Printer.Canvas.Draw(10, 5, b);
    Canvas.Font.Name := 'Courier New';                                   //  Ab hier ist alles wie es sein soll
    Canvas.Font.Size := 10;
    Canvas.Font.Bold := True;
    Canvas.Font.Color := clBlack;
    LineHeight := Round(1.1 * Abs(Canvas.TextHeight('I')));
    VerticalMargin := 2 * LineHeight;
    // There we go
    YPos := VerticalMargin + round(Image1.Picture.Graphic.Height / 33);
    j := Memo_Output.Lines.Count - 1;
    for i := 0 to j do
    begin
      zeile := Memo_Output.Lines[i];
      if pos('###', zeile) <> 0 then
      begin
        canvas.Font.Size := 13;
        Canvas.TextOut(LEFTMARGIN, YPos, zeile);
        YPos := YPos + LineHeight;
        canvas.Font.Size := 10;
        continue;
      end;

      if i = Memo_Output.Lines.Count - 1 then
        canvas.Font.Size := 25;
      zeile := dupestring(' ', 3) + trim(zeile);
      Canvas.TextOut(LEFTMARGIN, YPos, zeile);
      YPos := YPos + LineHeight;
    end;
    Canvas.Font.Size := 10;
    YPos := YPos + VerticalMargin;
    zeile := IntToStr(config.bonCount) + dupestring(' ', 7) + DateTimeToStr(Now);

    Canvas.TextOut(LEFTMARGIN, YPos, zeile);
    YPos := YPos + VerticalMargin;
    Canvas.TextOut(LEFTMARGIN, YPOS, ' ');
    YPos := YPos + VerticalMargin;
    Canvas.TextOut(LEFTMARGIN, YPOS, IntToStr(round(Image1.Picture.Graphic.Width / 33)) +
      '.......' + IntToStr(round(Image1.Picture.Graphic.Height / 33)));
    YPos := YPos + VerticalMargin;
    Canvas.TextOut(LEFTMARGIN, YPOS, error);

  finally
    EndDoc;
    DBStoreDish();
    DBStoreIngredients();
    DBWriteBon();
    config.printed := True;
    config.cash[1] := 0;
    config.additionalDish.Clear;
    config.main_dish := 0;
    resetall();
    config.additionalDish.Clear;
    PageControl1.ActivePageIndex := 0;
    config.bonCount := config.bonCount + 1;
    LblCounter.Caption := 'Count ' + IntToStr(config.bonCount);
    fillMemo(Memo_Output);
    config.printed := False;
  end;

end;
 
Vielen Dank schoneinmal
MfG
Beach

Shit happens... Always in my shift

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1639
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: Drucken eines PNG Logo auf einen "Kassenbon"

Beitrag von fliegermichl »

Also im Prinzip funktioniert es. Ich hab es getestet mit Windows 11 Drucker ist "Microsoft Print to PDF"
die Unit printers muß eingebunden werden und im Formular habe ich einen TPrintDialog mit Namen pd platziert.

Code: Alles auswählen

procedure TForm1.Button1Click(Sender: TObject);
var p : TPortableNetworkGraphic;
begin
  p := TPortableNetworkGraphic.Create;
  p.Width:=200;
  p.Height:=200;
  p.Canvas.Brush.Color := clWhite;
  p.Canvas.Pen.Color := clBlack;
  p.Canvas.Rectangle(Rect(0, 0, 200, 200));
  p.Canvas.moveTo(0, 0);
  p.Canvas.LineTo(100, 100);
  if pd.Execute then
  begin
    with Printer do
    begin
      BeginDoc;
      Canvas.Draw(0, 0, p);
      EndDoc;
    end;
  end;
end;

PoldiSH
Beiträge: 3
Registriert: Di 17. Jan 2012, 11:05

Re: Drucken eines PNG Logo auf einen "Kassenbon"

Beitrag von PoldiSH »

Moin,

mir fällt auf das in Deinem Code-Beispiel evtl. folgender Fehler ist:

Code: Alles auswählen

with Printer do
  try
    BeginDoc;
    Printer.Canvas.Draw(10, 5, b);
    Canvas.Font.Name := 'Courier New';                                   //  Ab hier ist alles wie es sein soll
Müsste in der vierten Zeile nicht das vorangestellte "Printer." weg gelassen werden ?

Nur so ein Gedanke...

Schönen Tag, PoldiSH

wp_xyz
Beiträge: 5129
Registriert: Fr 8. Apr 2011, 09:01

Re: Drucken eines PNG Logo auf einen "Kassenbon"

Beitrag von wp_xyz »

Beach hat geschrieben: Di 14. Mai 2024, 22:43

Code: Alles auswählen

try
    b := TPortableNetworkGraphic.Create;
    //  b.Transparent:= false;
    b.Canvas.Brush.Color := clBlue;
    b.Canvas.Rectangle(0, 0, round(Image1.Picture.Graphic.Width / 33),
      round(Image1.Picture.Graphic.Height / 33));
    b.Assign(Image1.Picture.Graphic);
  except
    error := 'Fehler beim Bilderzeugen';
  end;
Ich denke mal (ohne etwas ausprobiert zu haben), dass du dem PNG das linke obere 33-tel des gesamten Bildes zugewiesen hast, und wenn da "weiß" ist, siehst du nichts im Ausdruck.

Beim Drucken ist zu beachten, dass der Drucker eine andere Auflösung hat als der Bildschirm. Und wenn eine TImageKomponente zwischenschaltet ist, die evtl. ihrerseits skaliert, wird es doppelt kompliziert.

Generell würde ich das Ausgangsbild (Image1.Picture.Graphic) mit StretchDraw auf den Canvas des Druckers übertragen; das skaliert das Ausgangsbild auf ein anzugebendes Rechteck. Die Größe des Rechtecks muss aus der wahren Bildgröße (Image1.Picture.Width oder Image1.Picture.Graphic.Width, nicht aber Image.Width!, Height analog dazu) und der Druckerauflösung berechnet werden, wobei man, wenn man's genau nimmt, auch noch unterschiedliche Auflösungen in X und Y-Richtung berücksichtigen muss, was zumindest bei Druckern häufig der Fall ist.

Der folgende Code (ungetestet) sollte das Ausgangsbild (Größe wImg x hImg Pixel) ohne Verzerrung auf einem Rechteck von 5 cm Breite ausdrucken (5 mm Rand nach links und oben):

Code: Alles auswählen

const 
  GEDRUCKTE_BREITE = 50;  //mm
  RAND = 5;  // mm
var
  wImg, hImg: Integer;   // Pixelgröße des Original-Bildes
  wPrn, hPrn: Integer;   // Maße des Bildes auf Drucker
  randLinks, randOben: Integer;      // Rand, in Drucker-Pixeln
begin
  wImg := Image1.Picture.Width;
  hImg := Image1.Picture.Height;
  wPrn := round(GEDRUCKTE_BREITE / 25.4 * Printer.XDPI);
  hPrn := round(hImg/wImg*wPrn * Printer.YDPI / Printer.XDPI);   // ich hoffe, die Reihenfolge der Faktoren stimmt...
  randLinks := round(RAND / 25.4 * Printer.XDPI);
  randOben := round(RAND / 25.4 * Printer.YDPI);
  Printer.Canvas.StretchDraw(Rect(randLinks, randOben, randLinks + wPrn, randOben + hPrgn), Image1.Picture.Graphic)

Benutzeravatar
Beach
Lazarusforum e. V.
Beiträge: 60
Registriert: Di 2. Nov 2021, 22:41
OS, Lazarus, FPC: Lazarus 3.0RC1 (rev lazarus_3_0_RC1-10-gfe49fef4fc) FPC 3.2.2 x86_64-win64-win32
CPU-Target: 64Bit
Wohnort: Hunsrück

Re: Drucken eines PNG Logo auf einen "Kassenbon"

Beitrag von Beach »

Vielen Dank für die ganzen Tipps.
Nach einigem Verzweifeln weil es immer noch nicht geklappt hat, musste ich feststellen das das PNG (wahrscheinlich wegen Transparenzen) Ähnlichkeit mit der Ostfriesischen Nationalflagge hatte. Weißer Adler auf weißem Hintergrund.
Die Transparenz rausgenommen und siehe da schon klappt das.
Vielleich bekomme ich das ja doch noch bis Ende nächste Woche alles ans laufen :mrgreen:
MfG
Beach

Shit happens... Always in my shift

Joh
Lazarusforum e. V.
Beiträge: 280
Registriert: Sa 26. Mai 2012, 17:31
OS, Lazarus, FPC: Win 10 (L 2.2.6 x64 FPC 3.2.2)
CPU-Target: 64Bit

Re: Drucken eines PNG Logo auf einen "Kassenbon"

Beitrag von Joh »

Meine Frage dazu ist eher grundsätzlicher Art:
warum nimmst du ein Riesen-Logo und skalierst es beim Druck?

Klar, bei einem Foto, welches man einmalig druckt. Aber bei einem Kassenbon, der zigfach täglich gedruckt wird, würde ich das Bild bestmöglich auf die Druckqualität runterscalieren und dann einfach einfügen.
Rechenzeit ist auch Zeit, und Kassenrechner sind häufig aus der Zeit gefallen.
just my two Beer

Benutzeravatar
Beach
Lazarusforum e. V.
Beiträge: 60
Registriert: Di 2. Nov 2021, 22:41
OS, Lazarus, FPC: Lazarus 3.0RC1 (rev lazarus_3_0_RC1-10-gfe49fef4fc) FPC 3.2.2 x86_64-win64-win32
CPU-Target: 64Bit
Wohnort: Hunsrück

Re: Drucken eines PNG Logo auf einen "Kassenbon"

Beitrag von Beach »

Da gäbe es jetzt mehrere Antworten drauf.
- Das Logo lag in dem Format vor und ich habe nicht weiter auf die Größe geachtet.
- Dämlichkeit meinerseits
- Dummheit meinerseits
- Unüberlegtheit weil ich einen leichten Zeitdruck dabei habe.
- weil es sich nun halt einmal so ergeben hat

Such dir das aus was dir am besten gefällt. :lol: :lol:
Es gibt keinen wirklichen Grund. Außer das ich dadurch wieder etwas gelernt habe.

Außerdem ist die Anwendung kein Kassenrechner, sondern sehr speziell auf meinen Anwendungsfall zugeschnitten. Als Basis dient momentan ein Laptop mit mehr als ausreichend Leistung.

Falls es Interessiert:
Wir haben eine Veranstaltung im Dorf (diesesmal eine Kirmes) wo es Mittagessen gibt. Die Gäste kommen ins Zelt, können Ihr Essen bestellen und direkt bezahlen.
Mit dem Programm erstelle ich dann einen doppelten Bestellbon, wovon einer vom Service eingesammelt wird und einer beim Gast bleibt.
So kann das Essen recht einfach, je nach Bestellung, ausgegeben und zum Gast gebracht werden. Der kann dann anhand seines Bons sehen was er wirklich bestellt hat.
Hatte das Programm ursprünglich für ein Schlachtfest gemacht. Da noch mit einem ASCII Logo. Das wollte ich dieses mal anders machen.
Außerdem ist das aktuell viel unfelxibler als ich es letztes Jahr gedacht hatte. Wodurch mir aktuell etwas die Zeit wegläuft.
MfG
Beach

Shit happens... Always in my shift

Benutzeravatar
gladio
Beiträge: 223
Registriert: Sa 21. Jun 2014, 06:15
OS, Lazarus, FPC: Win10-64 - aktuelle Lazarus/FPC Standard-Edition
CPU-Target: 64Bit
Wohnort: Rügen

Re: Drucken eines PNG Logo auf einen "Kassenbon"

Beitrag von gladio »

Hast du denn auch eine TSE eingebunden?
Kassensicherheitsverordnung!

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2805
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Drucken eines PNG Logo auf einen "Kassenbon"

Beitrag von m.fuchs »

gladio hat geschrieben: Do 16. Mai 2024, 08:40 Hast du denn auch eine TSE eingebunden?
Kassensicherheitsverordnung!
Die sagt nur aus, dass ein elektronisches Kassensystem oder eine Registrierkasse eine TSE braucht. Beach schreibt aber:
Beach hat geschrieben: Do 16. Mai 2024, 08:17 Die Gäste kommen ins Zelt, können Ihr Essen bestellen und direkt bezahlen. Mit dem Programm erstelle ich dann einen doppelten Bestellbon, wovon einer vom Service eingesammelt wird und einer beim Gast bleibt.So kann das Essen recht einfach, je nach Bestellung, ausgegeben und zum Gast gebracht werden.
Das ist kein Kassensystem, sondern eine Bestellverwaltung. Wenn zum Bezahlen eine offene Ladenkasse daneben steht (oder auch eine Registrierkasse mit TSE) ist das völlig ok.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Antworten