CYFROWY BARON • PROGRAMOWANIE • Zobacz wątek - Rozmiar TMetafile

Rozmiar TMetafile

dział ogólny

Rozmiar TMetafile

Nowy postprzez pioro700 » wtorek, 1 września 2020, 12:30

Witam
Napisałem mały programik do generowania i rysowania kodu kreskowego Code128. Wszystko w sumie gra i buczy ale mam zagwozdkę z wymiarami objektu TMetafile.
Ze względów praktycznych funkcja rysująca kreski używa TMetafileCanvas jako płótna. Objekt TMetafile otrzymuje rozmiar w pikselach ... po zakończonym rysowaniu kopiuję wynik do Clipboard (Clipboard()->Assign(metafile)) ... wszystko OK.
I teraz to czego nie mogę załapać. Kiedy podaję docelową szerokość i wysokość kodu kreskowego, fukcja go kreśli i zwraca objekt TMetafile jako rezultat. Rezultat pakuję do schowka i wklejam w np.
MS. Visio. I tu dzieje się coś dziwnego a mianowicie kiedy zmieniam żądaną szerokość i wysokość, w pewnym przedziale szerokości zmienia się jedynie wysokość, a po przekroczeniu pewnej wartości szerokości, wklejony obrazek jest nagle dwa razy większy.
KOD cpp:     UKRYJ  
BarcodeImage->Width = pWidth;
        BarcodeImage->Height = pHeight;

        std::auto_ptr<Code128> code128(new Code128(BarEdit->Text, WidthEdit->Text.ToInt(),
                                                                                           HeightEdit->Text.ToInt(), false,
                                                                                           CLB->Selected, true));
        std::auto_ptr<TMetafile> meta(new TMetafile);
        code128->DrawCodeToMetafile(meta.get());

       BarcodeImage->Picture->Metafile->Assign(meta.get());
       Clipboard()->Assign(meta.get());
 


Przykład :
szer. 106p, wys, 42p .... wklejony obrazek ma romiar 26,98 mm x 10,27 mm
szer. 108p, wys, 44p .... wklejony obrazek ma romiar 26,98 mm x 10,51 mm
szer. 110p, wys, 46p .... wklejony obrazek ma romiar 26,98 mm x 10,75 mm
szer. 112p, wys, 48p .... wklejony obrazek ma romiar 26,98 mm x 11,23 mm
... i nagle
szer. 114p, wys, 50p .... wklejony obrazek ma romiar 53,72 mm x 23,17 mm

Obrazek w programie powiększa się proporcjonalnie ...

Mógłby mnie ktoś oświecić o co tu chodzi? Wujek Google niewiele mi pomógł w temacie.


Pewnie sprawa jest dość prosta ... ale nie dla mnie.
Avatar użytkownika
pioro700
Bladawiec
Bladawiec
 
Posty: 44
Dołączył(a): niedziela, 29 lipca 2012, 11:36
Podziękował : 5
Otrzymał podziękowań: 0
System operacyjny: Win 10 PRO.
Kompilator: RAD Studio 10.2
SKYPE: pioro700
Gadu Gadu: 0
    WindowsChrome

Re: Rozmiar TMetafile

Nowy postprzez lukagrom » wtorek, 1 września 2020, 13:18

Nie znam odpowiedzi, tyle, że widzę nieścisłość dotyczącą skalowania. Szerokość rośnie od 106p w przyroście 2, do 112p, a tymczasem wklejony obraz ma wymiarr const - 26,98mm. Problem ten nie występuje przy zwiększaniu wysokości. Ja dla odmiany napisałem coś bazującego na TCanvas do wykreślania fraktali. Żeby było śmieszniej niektóre wymiary płótna nie były obsługiwane, tj wygładało to jakby ekran był podzielone na pionowe pasy i w niektórych lokalizacjach TCanvas nie był obsługiwany. Na forach graficznych dowiedziałem się, że właśnie aparat graficzny w Delphi/C++ Builder jest toporny i pełen błędów.
Avatar użytkownika
lukagrom
Intelektryk
Intelektryk
 
Posty: 129
Dołączył(a): wtorek, 1 stycznia 2013, 14:54
Podziękował : 9
Otrzymał podziękowań: 5
System operacyjny: Windows Vista
Kompilator: C++ Builder 10.1 Starter
Gadu Gadu: 0
    WindowsChrome

Re: Rozmiar TMetafile

Nowy postprzez pioro700 » wtorek, 1 września 2020, 15:02

Nie do końca jestem w stanie rozwiązać wszystkie problemy ale znalazłem podstawowy błąd. Funkcja rysująca oblicza szerokość modułu kodu kreskowego na podstawie podanej docelowej szerokości. Szerokość może być podawana bądź w milimetrach, bądź w pikselach. Każdy znak kodu to 11 modułów zapisanych w 3 grupach (np. 21 32 14). Każda grupa to kreska i przerwa gdzie pierwsza cyfra określa ilość modułów kreski a druga ilość modułów przerwy. Jako, że wartość modułu może być tylko liczbą całkowitą, więc płótno na którym rysuję kod ma jedynie przybliżoną szerokość do tej żądanej.

Przykład:
żądana szerokość = 106p, ilość modułów = 128 ... szerokość modułu = 106/128 = 0,828125
Jako, że moduł jest liczbą całkowitą, to jego wartość będzie równa 1, wtedy szerokość płótna = 128 * 1 = 128.
...
...
aż dochodzę do szerokości = 129. wtedy pojawia się szerokość modułu 1 i mała wartość po przecinku, wtedy funkcjia ceil zaokrąglała wartoć modułu do 2 i nagle płótno stawało się dwa razy szersze ....

Ale to wszystko do czego doszedłem.
Nie wiem też jak narysować wypełniony prostokąt aby wypełnienie miało wymiar prostokąta bo funkcja Canvas->FillRect owsze, rysuje wypelniony prostokąt ale przesunięty do góry i w lewo o wartość .... właśnie czego ???
Kiedy kreski kodu rysuję za pomocą tej właśnie funkcji, to pierwsz kreska której górny-lewy punkt ma wartości 0,0, jest "niedorysowana" na dole i po prawej. Po ostatniej kresce jest puste miejsce o szerokości .... po raz kolejny ... czego???

Jak mogę to skorygować ?? Ma ktoś może jakieś pomysły ??
Avatar użytkownika
pioro700
Bladawiec
Bladawiec
 
Posty: 44
Dołączył(a): niedziela, 29 lipca 2012, 11:36
Podziękował : 5
Otrzymał podziękowań: 0
System operacyjny: Win 10 PRO.
Kompilator: RAD Studio 10.2
SKYPE: pioro700
Gadu Gadu: 0
    WindowsChrome

Re: Rozmiar TMetafile

Nowy postprzez lukagrom » wtorek, 1 września 2020, 16:19

FillRect jesli sie nie myle, to 4 wspolrzedne, 2 pierwsze to lewy gorny rog prostokata, 2 ostatnie to prawy dolny rog prostokata. Jesli to nie jest intuicyjne dla przeksztalcen, to na szybko napisalem funkcje wykreslajaca prostokat przy podaniu srodka prostokata (x,y) i jego dlugości i wysokości.
KOD cpp:     UKRYJ  
void __fastcall TForm1::wypelniony_Prost(int sr_x,int sr_y, int dl, int wys)
{
        int x1,y1,x2,y2;
        x1=sr_x-(dl/2);
        y1=sr_y-(wys/2);
        x2=sr_x+(dl/2);
        y2=sr_y+(dl/2);
        Form1->Canvas->FillRect(Rect(x1,y1,x2,y2));
}
 
Avatar użytkownika
lukagrom
Intelektryk
Intelektryk
 
Posty: 129
Dołączył(a): wtorek, 1 stycznia 2013, 14:54
Podziękował : 9
Otrzymał podziękowań: 5
System operacyjny: Windows Vista
Kompilator: C++ Builder 10.1 Starter
Gadu Gadu: 0
    WindowsChrome

Re: Rozmiar TMetafile

Nowy postprzez pioro700 » wtorek, 1 września 2020, 19:05

Dzięki za dobre chęci ale nie do końca o to mi chodziło.
Funkcja FillRect() wypełnia wnętrze określonego przez TRect prostokąta. Wypełnienie obejmuje górną i lewą krawędż prostokąta a pomija dolną i prawą. Efekt jest taki na załączonym obrazku.
Bez względu na to czy używasz wymiarowania opartego na środku prostokąta, czy na jego górnym prawym rogu, efekt zawsze będzie taki sam jeśli nie znasz tego magicznego "EDGE" .... a ja go nie znam i nie wiem jak przesunąć wypełniony prostokąt w granice pola określonego przez Top, Left, Width i Height. ...
Nie masz wystarczających uprawnień, aby zobaczyć pliki załączone do tego postu.
Avatar użytkownika
pioro700
Bladawiec
Bladawiec
 
Posty: 44
Dołączył(a): niedziela, 29 lipca 2012, 11:36
Podziękował : 5
Otrzymał podziękowań: 0
System operacyjny: Win 10 PRO.
Kompilator: RAD Studio 10.2
SKYPE: pioro700
Gadu Gadu: 0
    WindowsChrome

Re: Rozmiar TMetafile

Nowy postprzez lukagrom » wtorek, 1 września 2020, 22:22

Na tym obrazku wychodzi, że cztery argumenty FillRect powinny być dodane o tę samą wartość (może są zaniżone w obliczeniach i lewy górny róg czyli x1,y1 dostaje np wartosci ujemne i wychodzi poza ramy Rect). Tu ewidentnie ma pójść cała figura ku prawemu dołowi, czyli powtórzę się - wszystkie cztery argumenty powinny być dodane o jakiś x. Od biedy taki x można sobie na "oko" wyliczyć, metodą prób i błędów, by kolejno nanoszone wartości dodawanych składników idealnie wpisały się w ramy prostokąta. Być może Rect ma domyślnie nastawioną włąsciwość typu margin lub coś podobnego i o taką wartość należy dodawać współrzędne do wypełnienia.
Avatar użytkownika
lukagrom
Intelektryk
Intelektryk
 
Posty: 129
Dołączył(a): wtorek, 1 stycznia 2013, 14:54
Podziękował : 9
Otrzymał podziękowań: 5
System operacyjny: Windows Vista
Kompilator: C++ Builder 10.1 Starter
Gadu Gadu: 0
    WindowsChrome

Re: Rozmiar TMetafile

Nowy postprzez lukagrom » wtorek, 1 września 2020, 23:01

Tutaj znalazłem kod Delphi, gdzie dla TRect uwzględniany jest właśnie margines przesunięcia obrazu:
KOD cpp:     UKRYJ  
  begin
    result := TRect.Create(0, 0, ThisControl.ClientWidth, ThisControl.ClientHeight);
    result.Left += ThisControl.Border.Left.Padding;
    result.Top += ThisControl.Border.Top.Padding;
    result.Right -= ThisControl.Border.Right.Padding;
    result.Bottom -= ThisControl.Border.Bottom.Padding;
 
 
Avatar użytkownika
lukagrom
Intelektryk
Intelektryk
 
Posty: 129
Dołączył(a): wtorek, 1 stycznia 2013, 14:54
Podziękował : 9
Otrzymał podziękowań: 5
System operacyjny: Windows Vista
Kompilator: C++ Builder 10.1 Starter
Gadu Gadu: 0
    WindowsChrome

Re: Rozmiar TMetafile

Nowy postprzez pioro700 » środa, 2 września 2020, 00:40

Kod który wkleiłeś musi być wycinkiem czegoś większego. Ja nie mogę tego rozgryźć.
Konstruktory TRect dla Delphi
Kod: Zaznacz cały
constructor Create(const Origin: TPoint); overload;                              // empty rect at given origin
    constructor Create(const Origin: TPoint; Width, Height: Integer); overload;      // at TPoint of origin with width and height
    constructor Create(const Left, Top, Right, Bottom: Integer); overload;           // at x, y with width and height
    constructor Create(const P1, P2: TPoint; Normalize: Boolean = False); overload;  // with corners specified by p1 and p2
    constructor Create(const R: TRect; Normalize: Boolean = False); overload;


Wartość
lukagrom napisał(a):Na tym obrazku wychodzi, że cztery argumenty FillRect powinny być dodane o tę samą wartość (może są zaniżone w obliczeniach i lewy górny róg czyli x1,y1 dostaje np wartosci ujemne i wychodzi poza ramy Rect). Tu ewidentnie ma pójść cała figura ku prawemu dołowi, czyli powtórzę się - wszystkie cztery argumenty powinny być dodane o jakiś x.


No właśnie wcześniej to napisałem, że jest to wartość "edge", cokolwiek to znaczy i funkcja FillRect robi to sama z siebie wypełniając górną i lewą krawędź prostokąta a pomijając wypełnienie krawędzi dolnej i prawej co daje taki efekt.
FillRect Fills the specified rectangle on the canvas using the current brush.
Use FillRect to fill a rectangular region using the current brush. The region is filled including the top and left sides of the rectangle, but excluding the bottom and right edges.


Jest to prawdopodobnie wartość jednego piksela ale jak przesuwam wszystko o 1 to rezultat tego nie potwierdza.

Zastosowałem inną funkcję a mianowicie virtual void __fastcall Polygon(const System::Types::TPoint *Points, const int Points_High); i jest to właśnie to czego szukałem.
Wpisując cztery współrzędne wierzchołków prostokąta, funkcja wypełnia je kolorem podanym przez Canvas->Brush->Color.

Za nic jednak nie mogę dojść do ładu z rozmiarem płótna. Nie wiem jak przeliczyć milimetry na piksele. Jeżeli używam piksele = milimetry * 3.77952755905511 to mimo iż przydzielam Image takie same rozmiary jak płótno, to i tak wygenerowany obrazek kodu kreskowego nie wypełnia tego płótna.
Avatar użytkownika
pioro700
Bladawiec
Bladawiec
 
Posty: 44
Dołączył(a): niedziela, 29 lipca 2012, 11:36
Podziękował : 5
Otrzymał podziękowań: 0
System operacyjny: Win 10 PRO.
Kompilator: RAD Studio 10.2
SKYPE: pioro700
Gadu Gadu: 0
    WindowsChrome

Re: Rozmiar TMetafile

Nowy postprzez lukagrom » środa, 2 września 2020, 10:26

Bardzo dawno temu zakupiłem fajną książkę -"C++ Builder. 20 efektownych programów" Andrzeja Stasiewicza i tam jest opisana bardzo przydatna klasa, która przelicza współrzędne ekranowe na rzeczywiste i na odwrót, czyli rzeczywiste na ekranowe przy zachowaniu odpowiedniej skali. Może się przyda w tym badanym założeniu milmetry-piksele.

KOD cpp:     UKRYJ  

class TSkalowanie
{
        private:
        double A,B,C,D;
        double E,F,G,H;
        public:
        TSkalowanie(int xe0, int ye0,int eszer,int ewys,double xr0,double yr0,
        double rszer, double rwys);
        int daj_ekr_x(double xr);
        int daj_ekr_y(double yr);
        double daj_real_x(int xe);
    double daj_real_y(int ye);
};


TSkalowanie::TSkalowanie(int xe0, int ye0, int eszer, int ewys, double xr0,
double yr0, double rszer, double rwys)
{
        A=(double) eszer/rszer;
        B=(double) xe0-A*(xr0-rszer/2.);
        C=-(double) ewys/rwys;
        D=(double)ye0-C*(yr0+rwys/2.);
        E=rszer/(double)eszer;
        F=xr0-rszer/2.-E*(double)xe0;
        G=-rwys/(double)ewys;
        H=yr0+rwys/2.-G*(double)ye0;
}
int TSkalowanie::daj_ekr_x(double x)
{
        return (int)(A*x+B);
}
int TSkalowanie::daj_ekr_y(double y)
{
        return (int)(C*y+D);

}
double TSkalowanie::daj_real_x(int xe)
{
        return E*xe+F;
}
double TSkalowanie::daj_real_y(int ye)
{
    return G*ye+H;
}
 

 


Przykład użycia powiedzmy dla wykreslenia pikseli na ekranie z granicy liczb rzeczywistych powiedzmy x=1...100,y=1..100
KOD cpp:     UKRYJ  
TSkalowanie my_Rect(0,0,ClientWidth,ClientHeight,1,100,1,100);
int pix_X, pix_Y;
for(int i=1;i<100;i++)
{
 pix_X=my_Rect.daj_ekr_x(1,0*i);
 pix_Y=my_Rect.daj_ekr_y(1.0*i);
 Canvas->Pixels[pix_X][pix_Y]=clBlack;
}

 
Avatar użytkownika
lukagrom
Intelektryk
Intelektryk
 
Posty: 129
Dołączył(a): wtorek, 1 stycznia 2013, 14:54
Podziękował : 9
Otrzymał podziękowań: 5
System operacyjny: Windows Vista
Kompilator: C++ Builder 10.1 Starter
Gadu Gadu: 0
    UbuntuFirefox

Re: Rozmiar TMetafile

Nowy postprzez pioro700 » środa, 2 września 2020, 20:02

Dzięki raz jeszcze. Klasa fajna ale nie wiem do czego mógłbym jej użyć w moim programie.
Prawdopodobnie moim problemem jest ustawienie rozmiarów objektu umieszczonego w pamięci.
Spróbuję to pokazać krok po kroku.

1 Tworzę klasę Code128 :
Kod: Zaznacz cały
std::auto_ptr<Code128> code128(new Code128(BarEdit->Text, width, height, unit,  lineColor, true));

parametry wejściowe to : ciąg tekstowy, żądana szerokość kodu, żądana wysokość kodu, jednoski wymiaru(mm/piksele), kolor kresek, wskaźnik zastosowania białego tła
konstruktor wywołuje funkcje obliczające, ilość znaków kodu, ilość modułów, szerokość modułu, rozmiar płótna do rysowania oraz rozmiar płótna podany przez użytkownika

2. Tworzę objekt typu TMetafile i wywołuję funkcję rysującą kod kreskowy.
Kod: Zaznacz cały
std::auto_ptr<TMetafile> meta(new TMetafile);
   code128->TestDrawCode(meta.get());

   BarcodeImage->Picture->Metafile->Assign(meta.get());
   Clipboard()->Assign(meta.get());

funkcja rysująca przypisuje obbjektowi meta rozmmiar podany przez użytkownika oraz tworzy płótno dla tego objektu. Tworzy nowy objekt TMetafile o rozmiarach płótna do rysowania i nowe płótno dla tego objektu. Rysuje kreski na płótnie tymczasowego objektu. Po zakończeniu rysowania tymczasowemu objektowi przypisywane są rozmiary takie same jak meta i na płótnie meta rysuje kreski objektu tymczasowego
Kod: Zaznacz cały
metaCanv->Draw(0,0, cpyMeta);
.... (chyba niźle nagmatwałem)...

No i sedno problemu jest w tym , że na docelowym płótnie mam idealny kod kreskowy .... ale z pustym pasem na dole i po prawej stronie obrazu.
Pusty pas jest jeszcze szerszy jeśli użyję funkcji StretchDraw zamiast Draw. :roll:
Avatar użytkownika
pioro700
Bladawiec
Bladawiec
 
Posty: 44
Dołączył(a): niedziela, 29 lipca 2012, 11:36
Podziękował : 5
Otrzymał podziękowań: 0
System operacyjny: Win 10 PRO.
Kompilator: RAD Studio 10.2
SKYPE: pioro700
Gadu Gadu: 0
    WindowsChrome

Re: Rozmiar TMetafile

Nowy postprzez lukagrom » środa, 2 września 2020, 20:39

A może jeszcze przed wywołaniem Draw(), ustawić:
Kod: Zaznacz cały
cpyMeta->TransparentMode=tmAuto;
Avatar użytkownika
lukagrom
Intelektryk
Intelektryk
 
Posty: 129
Dołączył(a): wtorek, 1 stycznia 2013, 14:54
Podziękował : 9
Otrzymał podziękowań: 5
System operacyjny: Windows Vista
Kompilator: C++ Builder 10.1 Starter
Gadu Gadu: 0
    UbuntuFirefox

Re: Rozmiar TMetafile

Nowy postprzez pioro700 » środa, 2 września 2020, 21:25

TMetafile nie ma takiej właściwości ...
Załączam obrazek jak to wygląda ... czerwone tło jest tylko dla zaznaczenia pustego miejsca, w rzeczywistości puste miejsce jest transparentne.
Nie masz wystarczających uprawnień, aby zobaczyć pliki załączone do tego postu.
Avatar użytkownika
pioro700
Bladawiec
Bladawiec
 
Posty: 44
Dołączył(a): niedziela, 29 lipca 2012, 11:36
Podziękował : 5
Otrzymał podziękowań: 0
System operacyjny: Win 10 PRO.
Kompilator: RAD Studio 10.2
SKYPE: pioro700
Gadu Gadu: 0
    WindowsChrome

Re: Rozmiar TMetafile

Nowy postprzez pioro700 » czwartek, 3 września 2020, 10:01

Problem w 99% rozwiązany. Może się kiedyśkomuś przyda

Przeliczanie pikseli na milimetry i odwrotnie
Kod: Zaznacz cały
HDC screen = GetDC(NULL);
int hSize=GetDeviceCaps(screen,HORZSIZE);
int hRes=GetDeviceCaps(screen,HORZRES);
float PixelsPerMM=(float)hRes/hSize;   // pikseli na milimetr
float PixelsPerInch=PixelsPerMM*25.4; //dpi

Co do pustej ramki, spowodowana jest zaokrąglaniem wyników (wrtości pikseli na milimetr i odwrotnie podawane są z ośmioma cyframi po przecinku). Rozwiązaniem jest dodanie po jednym pikselu do szerokości i wysokości ponad wartości podane przez użytkownika jako wartości docelowe, objektowi źródłowemu.

Kod: Zaznacz cały
TMetafile *cpyMeta = new TMetafile;                  // objekt  na którego płótnie ryowany będzie kod kreskowy
   cpyMeta->Enhanced = true;
   cpyMeta->SetSize(this->cWidth, this->cHeight);    // szerokość jest ilorazem szerokości modułu i ilości modułów w kodzie kreskowym a
                                                                                  // szerokość jest proporcjonalnie zwiększona/zmniejszona do szerokości
                 
   TMetafileCanvas *cpyCanv = new TMetafileCanvas(cpyMeta, 0);               // płótno objektu cpyMeta
...
...
...
        delete cpyCanv;
   cpyMeta->SetSize(this->pxWidth + 1, this->pxHeight + 2);

   meta->Enhanced = true;
   if(this->orgMilis) // rozmiar ramki kodu podany w milimetrach
      {
         cpyMeta->MMWidth = this->mmWidth + (_pixelToMilis(1.0f * 100));
         cpyMeta->MMHeight = this->mmHeight + (_pixelToMilis(1.5f * 100));
         meta->MMWidth = this->mmWidth;
         meta->MMHeight = this->mmHeight;
      }
   else
      meta->SetSize(this->pxWidth, this->pxHeight);

   TMetafileCanvas *metaCanv = new TMetafileCanvas(meta, 0);

   metaCanv->Draw(0,0, cpyMeta);

Avatar użytkownika
pioro700
Bladawiec
Bladawiec
 
Posty: 44
Dołączył(a): niedziela, 29 lipca 2012, 11:36
Podziękował : 5
Otrzymał podziękowań: 0
System operacyjny: Win 10 PRO.
Kompilator: RAD Studio 10.2
SKYPE: pioro700
Gadu Gadu: 0
    WindowsChrome


  • Podobne tematy
    Odpowiedzi
    Wyświetlone
    Ostatni post

Powrót do Ogólne problemy z programowaniem

Kto przegląda forum

Użytkownicy przeglądający ten dział: Brak zalogowanych użytkowników i 2 gości

cron