Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
Etichettatore - main.cpp

main.cpp

Caricato da: AldoBaldo
Scarica il programma completo

  1. #include <windows.h>
  2. #include <gdiplus.h>
  3. using namespace Gdiplus;
  4. #include "risorse.h"
  5.  
  6. /// ===> COSTANTI <=============================================================
  7.  
  8. const char kStrNomeProgramma[]      = "Etichettatore";
  9. const char kStrInfo[] =
  10. "Etichettatore \nv1.0, agosto 2015 \n di Aldo Carpanelli ";
  11. const char kStrGDIPlusNonIniz[]     = "GdiPlus non inizializzato.";
  12. const char kStrImgNonIniz[]         = "Impossibile creare l'immagine.";
  13. const char kStrSalvataggioFallito[] = "Etichette non salvate.";
  14. const char kStrErrIndefinito[]      = "Errore indefinito";
  15. const char kStrWCasInsensata[] =
  16. "La larghezza attribuita alle caselle è insensata. \n\
  17. Ripristino i valori predefiniti.";
  18. const char kStrHCasInsensata[] =
  19. "L'altezza attribuita alle caselle è insensata. \n\
  20. Ripristino i valori predefiniti.";
  21. const char kStrHFntInsensata[] =
  22. "L'altezza attribuita al font è insensata. \n\
  23. Ripristino i valori predefiniti.";
  24. const char kStrSalvataggioOk[] =
  25. "Etichette salvate nel file \"etichette.png\", \n\
  26. collocato nella stessa cartella ove si trova \n\
  27. il programma.";
  28. const WCHAR kStrNomeFont[] = L"Arial";
  29. const WCHAR kStrNomeFile[] = L"etichette.png";
  30.  
  31. const REAL kPixelPerMM = 300.0/25.4; // un fattore di conversione
  32. const REAL kWPag = 210.0f;           // la classica larghezza dei fogli A4
  33. const REAL kHPag = 297.0f;           // la classica altezza dei fogli A4
  34.  
  35. // lo spessore del tratto per il tracciamento dei crocini
  36. const REAL kWTratto = 0.2f * kPixelPerMM;
  37. // il raggio dei crocini
  38. const REAL kRCrocino = 3.0f * kPixelPerMM;
  39.  
  40. const REAL kWCasDflt = 50.0f;
  41. const REAL kHCasDflt = kWCasDflt*0.4f;
  42. const REAL kHFntDflt = kHCasDflt*0.5f;
  43.  
  44. // la quantita' massima dei caratteri per il testo d'una etichetta
  45. const int kDimTCas = 255;
  46.  
  47.  
  48. /// ===> VARIABILI GLOBALI <====================================================
  49.  
  50. /*
  51. Lo so che ogni programmatore che si rispetti aborre le variabili globali, ma...
  52.  
  53.     1. io non sono un programmatore che si rispetti
  54.     2. in un programma di dimensioni cosi' ridotte non fanno male
  55. */
  56.  
  57. RECT gRAp;                  // il rettangolo dell'anteprima
  58. Bitmap *gBmp = NULL;        // l'immagine
  59. Graphics *gGfxBmp = NULL;   // oggetto Graphics per tracciare su gBmp
  60.  
  61. REAL gWCas, gHCas;  // dimensioni delle caselle
  62. int gNOCas, gNVCas; // quantita' delle caselle in orizzontale e in verticale
  63. REAL gHFnt;         // dimensioni del font (in millimetri)
  64. char gTCas[kDimTCas+1] = "Testo";
  65. char gNum = 0; // se non 0, aggiunge un numero d'ordine al testo delle caselle
  66.  
  67. HINSTANCE gHInst;
  68.  
  69.  
  70. /// ===> PROTOTIPI DELLE FUNZIONI <=============================================
  71.  
  72. BOOL CALLBACK DlgMain( HWND hwnd, UINT msg, WPARAM wPar, LPARAM lPar );
  73. bool CreaImmagine( void );
  74. void DismettiImmagine( void );
  75. void InizializzaDialogo( HWND hwnd );
  76. void AcquisisciDati( HWND hwnd );
  77. void ImpostaValoriPredefiniti( void );
  78. void CalcolaQuantitaCaselle( void );
  79. void MostraDati( HWND hwnd );
  80. void TracciaImmagine( Graphics *gfx );
  81. void TracciaAnteprima( HDC hdc );
  82. bool SalvaImmagine( HWND hwnd );
  83. void Info( const char *msg, HWND hwnd = NULL );
  84. void Errore( const char *msg, HWND hwnd = NULL );
  85. UINT InizializzaGdiPlus( void );
  86. void DismettiGdiPlus( void );
  87.  
  88.  
  89. /// ===> DEFINIZIONE DELLE FUNZIONI <===========================================
  90.  
  91. int APIENTRY WinMain(
  92.     HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR cmdLine, int nShow ) {
  93.  
  94.     int esito = 0;
  95.  
  96.     gHInst = hInst;
  97.  
  98.     if( !InizializzaGdiPlus() ) { Errore( kStrGDIPlusNonIniz ); return 0; }
  99.  
  100.     if( !CreaImmagine() ) { Errore( kStrImgNonIniz ); return 0;  }
  101.  
  102.     esito = DialogBox(
  103.         hInst, MAKEINTRESOURCE(IDD_DIALOGO), NULL, (DLGPROC)DlgMain );
  104.  
  105.     DismettiImmagine();
  106.     DismettiGdiPlus();
  107.     return esito;
  108. }
  109.  
  110.  
  111. BOOL CALLBACK DlgMain( HWND hwnd, UINT msg, WPARAM wPar, LPARAM lPar ) {
  112.     switch(msg) {
  113.         case WM_INITDIALOG: {
  114.             ImpostaValoriPredefiniti();
  115.             InizializzaDialogo( hwnd );
  116.             // forza il tracciamento iniziale dell'anteprima
  117.             SendMessage( hwnd, WM_COMMAND, MAKELONG(IDOK,1), 0 );
  118.             } return TRUE;
  119.  
  120.         case WM_CLOSE: {
  121.             EndDialog( hwnd, 0 );
  122.             } return TRUE;
  123.  
  124.         case WM_COMMAND: {
  125.             switch( LOWORD(wPar) ) {
  126.                 case IDOK:
  127.                     AcquisisciDati( hwnd );
  128.                     TracciaImmagine( gGfxBmp );
  129.                     InvalidateRect( hwnd, &gRAp, FALSE );
  130.                     break;
  131.                 case IDCANCEL:
  132.                     EndDialog( hwnd, 0 );
  133.                     break;
  134.                 case IDC_SALVA:
  135.                     TracciaImmagine( gGfxBmp );
  136.                     InvalidateRect( hwnd, &gRAp, FALSE );
  137.                     SalvaImmagine( hwnd );
  138.                     break;
  139.                 case IDC_NUMERA:
  140.                     gNum = !gNum;
  141.                     TracciaImmagine( gGfxBmp );
  142.                     InvalidateRect( hwnd, &gRAp, FALSE );
  143.                     break;
  144.                 case IDC_INFO:
  145.                     Info( kStrInfo, hwnd );
  146.                     break;
  147.                 default:
  148.                     ;
  149.             }
  150.             } return TRUE;
  151.  
  152.         case WM_PAINT: {
  153.             PAINTSTRUCT ps;
  154.             HDC hdc = BeginPaint( hwnd, &ps );
  155.             TracciaAnteprima( hdc );
  156.             EndPaint( hwnd, &ps );
  157.             } return TRUE;
  158.         default:
  159.             ;
  160.     } return FALSE;
  161. }
  162.  
  163.  
  164. /*==============================================================================
  165. Crea l'immagine in memoria e l'oggetto Graphics destinato a disegnare su di
  166. essa.
  167. ==============================================================================*/
  168.  
  169. bool CreaImmagine( void ) {
  170.     try {
  171.         DismettiImmagine(); // non si sa mai...
  172.  
  173.         gBmp = new Bitmap( round(kWPag*kPixelPerMM), round(kHPag*kPixelPerMM) );
  174.  
  175.         if( gBmp->GetLastStatus() == Ok ) {
  176.             gBmp->SetResolution( 300.0f, 300.0f );
  177.  
  178.             gGfxBmp = new Graphics( gBmp );
  179.  
  180.             if( gGfxBmp->GetLastStatus() == Ok ) {
  181.                 gGfxBmp->Clear( 0xFFFFFFFF );
  182.                 gGfxBmp->SetTextRenderingHint( TextRenderingHintAntiAlias );
  183.                 gGfxBmp->SetSmoothingMode( SmoothingModeAntiAlias );
  184.                 return true;
  185.             }
  186.             else {
  187.                 DismettiImmagine();
  188.                 return false;
  189.             }
  190.         }
  191.         else {
  192.             DismettiImmagine();
  193.             return false;
  194.         }
  195.     } catch( ... ) {
  196.         DismettiImmagine();
  197.         return false;
  198.     }
  199. }
  200.  
  201.  
  202. void DismettiImmagine( void ) {
  203.     delete gBmp;
  204.     gBmp = NULL;
  205.  
  206.     delete gGfxBmp;
  207.     gGfxBmp = NULL;
  208. }
  209.  
  210.  
  211. void CalcolaQuantitaCaselle( void ) {
  212.     gNOCas = round( kWPag/gWCas );
  213.     gNVCas = round( kHPag/gHCas );
  214.  
  215.     // verifica che si stia entro i limiti della pagina
  216.     if( gNOCas*gWCas > kWPag ) gNOCas -= 1.0f;
  217.     if( gNVCas*gHCas > kHPag ) gNVCas -= 1.0f;
  218. }
  219.  
  220.  
  221. void ImpostaValoriPredefiniti( void ) {
  222.     gWCas = kWCasDflt;
  223.     gHCas = kHCasDflt;
  224.     gHFnt = kHFntDflt;
  225.  
  226.     CalcolaQuantitaCaselle();
  227. }
  228.  
  229.  
  230. /*==============================================================================
  231. Valutando la posizione del controllo nascosto IDC_RIGA, calcola le dimensioni
  232. dello spazio riservato al margine intorno all'immagine d'anteprima nella
  233. finestra.
  234. ==============================================================================*/
  235.  
  236. int RicavaMargineAnteprima( HWND hwnd ) {
  237.     RECT wrCtrl;
  238.     GetWindowRect( GetDlgItem(hwnd,IDC_RIGA), &wrCtrl );
  239.     ScreenToClient( hwnd, (LPPOINT)&wrCtrl );
  240.     return wrCtrl.top;
  241. }
  242.  
  243.  
  244. /*==============================================================================
  245. Adatta la finestra alle esigenze dell'anteprima e imposta gRAp.
  246. ==============================================================================*/
  247.  
  248. void RegolaLarghezzaDlg( HWND hwnd, int bordoAp ) {
  249.     RECT crDlg, wrRiga, wrDlg;
  250.     INT sxAp;  // il margine sinistro dell'area dell'anteprima
  251.     INT hAp;   // l'altezza dell'area dell'anteprima
  252.     INT wAp;   // la larghezza dell'area dell'anteprima
  253.     INT wDlg;  // la nuova larghezza della finestra di dialogo
  254.  
  255.     GetClientRect( hwnd, &crDlg );
  256.     GetWindowRect( hwnd, &wrDlg );
  257.     GetWindowRect( GetDlgItem(hwnd,IDC_RIGA), &wrRiga );
  258.     sxAp = wrRiga.right - wrDlg.left;
  259.     ScreenToClient( hwnd, (LPPOINT)(&wrRiga) );
  260.     ScreenToClient( hwnd, ((LPPOINT)(&wrRiga))+1 );
  261.     hAp = crDlg.bottom - 2*bordoAp;
  262.     wAp = round(((REAL)hAp)*kWPag/kHPag);
  263.     wDlg = sxAp + 2*bordoAp + wAp + ((wrDlg.right-wrDlg.left)-crDlg.right)/2;
  264.     SetRect( &gRAp, sxAp, bordoAp, sxAp+wAp, bordoAp+hAp );
  265.     MoveWindow( hwnd, wrDlg.left, wrDlg.top, wDlg, wrDlg.bottom-wrDlg.top, TRUE );
  266. }
  267.  
  268.  
  269. void InizializzaDialogo( HWND hwnd ) {
  270.     // scopre l'ampiezza del margine intorno all'area dell'anteprima
  271.     int bordoAp = RicavaMargineAnteprima( hwnd );
  272.  
  273.     RegolaLarghezzaDlg( hwnd, bordoAp ); // adatta la finestra alle esigenze
  274.                                          // dell'anteprima e imposta gRAp
  275.  
  276.     SendDlgItemMessage( hwnd, IDC_WETICH, EM_LIMITTEXT, 3, 0 );
  277.     SendDlgItemMessage( hwnd, IDC_HETICH, EM_LIMITTEXT, 3, 0 );
  278.     SendDlgItemMessage( hwnd, IDC_TESTOETICH, EM_LIMITTEXT, kDimTCas, 0 );
  279.     SendDlgItemMessage( hwnd, IDC_DIMFONT, EM_LIMITTEXT, 3, 0 );
  280.  
  281.     MostraDati( hwnd );
  282.  
  283.     ShowWindow( GetDlgItem(hwnd,IDC_RIGA), SW_HIDE );
  284. }
  285.  
  286.  
  287. /*==============================================================================
  288. Esamina i controlli della finestra per rilevare i dati immessi dall'utente.
  289. Immagazzina nelle variabili piu' opportune i dati rilevati.
  290. ==============================================================================*/
  291.  
  292. void AcquisisciDati( HWND hwnd ) {
  293.     const int kDimBuff = 255;
  294.     char buff[kDimBuff+1] = "";
  295.  
  296.     GetDlgItemText( hwnd, IDC_WETICH, buff, kDimBuff );
  297.     gWCas = atof( buff );
  298.  
  299.     if( gWCas > kWPag || gWCas < 0.5f ) {
  300.         Errore( kStrWCasInsensata, hwnd );
  301.         ImpostaValoriPredefiniti();
  302.     }
  303.  
  304.     GetDlgItemText( hwnd, IDC_HETICH, buff, kDimBuff );
  305.     gHCas = atof( buff );
  306.  
  307.     if( gHCas > kHPag || gHCas < 0.5f ) {
  308.         Errore( kStrHCasInsensata, hwnd );
  309.         ImpostaValoriPredefiniti();
  310.     }
  311.  
  312.     GetDlgItemText( hwnd, IDC_TESTOETICH, gTCas, kDimTCas );
  313.  
  314.     GetDlgItemText( hwnd, IDC_DIMFONT, buff, kDimBuff );
  315.     gHFnt = atof( buff );
  316.  
  317.     if( gHFnt > gHCas || gHFnt < 0.5f ) {
  318.         Errore( kStrHFntInsensata, hwnd );
  319.         ImpostaValoriPredefiniti();
  320.     }
  321.  
  322.     gNum = SendDlgItemMessage( hwnd, IDC_NUMERA, BM_GETSTATE, 0, 0 ) == BST_CHECKED;
  323.  
  324.     CalcolaQuantitaCaselle();
  325.  
  326.     MostraDati( hwnd );
  327. }
  328.  
  329.  
  330. /*==============================================================================
  331. "Travasa" i valori delle variabili del programma nei campi della finestra.
  332. ==============================================================================*/
  333.  
  334. void MostraDati( HWND hwnd ) {
  335.     SetDlgItemInt( hwnd, IDC_WETICH, gWCas, FALSE );
  336.     SetDlgItemInt( hwnd, IDC_HETICH, gHCas, FALSE );
  337.     SetDlgItemInt( hwnd, IDC_ETICHXRIGA, gNOCas, FALSE );
  338.     SetDlgItemInt( hwnd, IDC_RIGHEXPAGINA, gNVCas, FALSE );
  339.     SetDlgItemInt( hwnd, IDC_TOTALEETICH, gNOCas*gNVCas, FALSE );
  340.     SetDlgItemText( hwnd, IDC_TESTOETICH, gTCas );
  341.     SetDlgItemInt( hwnd, IDC_DIMFONT, gHFnt, FALSE );
  342.  
  343.     if( gNum != 0 )
  344.         SendDlgItemMessage( hwnd, IDC_NUMERA, BM_SETCHECK, BST_CHECKED, 0 );
  345.     else SendDlgItemMessage( hwnd, IDC_NUMERA, BM_SETCHECK, BST_UNCHECKED, 0 );
  346. }
  347.  
  348.  
  349. WCHAR *CharStr2WCharStr( const char *s ) {
  350.     static WCHAR wBuff[kDimTCas+1];
  351.     int i, l = strlen( s );
  352.     for( i=0; i<l; ++i )
  353.         wBuff[i] = (unsigned char)(s[i]);
  354.     wBuff[i] = 0;
  355.     return wBuff;
  356. }
  357.  
  358.  
  359. /*==============================================================================
  360. Disegna le etichette nell'immagine gBmp, avvalendosi dei servizi dell'oggetto
  361. di classe Graphics passato come parametro in *gfx.
  362. ==============================================================================*/
  363.  
  364. void TracciaImmagine( Graphics *gfx ) {
  365.     Pen penna( 0xFF000000, kWTratto );
  366.     if( penna.GetLastStatus() != Ok ) return;
  367.  
  368.     SolidBrush nero( 0xFF000000 );
  369.     if( nero.GetLastStatus() != Ok ) return;
  370.  
  371.     Font font( kStrNomeFont, gHFnt*kPixelPerMM, FontStyleBold, UnitPixel );
  372.     if( font.GetLastStatus() != Ok ) return;
  373.  
  374.     const REAL wCas = gWCas*kPixelPerMM;
  375.     const REAL hCas = gHCas*kPixelPerMM;
  376.     const REAL wPag = kWPag*kPixelPerMM;
  377.     const REAL hPag = kHPag*kPixelPerMM;
  378.     const REAL iX = (wPag-gNOCas*wCas)/2.0f;
  379.     const REAL iY = (hPag-gNVCas*hCas)/2.0f;
  380.     REAL x1, y1, x2, y2;
  381.     int i=0, j=0, l=0, n=0;
  382.  
  383.     gfx->Clear( 0xFFFFFFFF );
  384.  
  385.     StringFormat sf;
  386.     sf.SetAlignment( StringAlignmentCenter );
  387.     sf.SetLineAlignment( StringAlignmentCenter );
  388.  
  389.     RectF rf( iX, iY, wCas, hCas );
  390.  
  391.     // traccia le parti verticoli dei crocini
  392.     for( i=0; i<=gNOCas; ++i ) {
  393.         x1 = x2 = iX + ((REAL)i)*wCas;
  394.         for( j=0; j<=gNVCas; ++j ) {
  395.             y1 = iY + ((REAL)(j*hCas)) - kRCrocino;
  396.             y2 = iY + ((REAL)(j*hCas)) + kRCrocino;
  397.             gfx->DrawLine( &penna, x1, y1, x2, y2 );
  398.         }
  399.     }
  400.  
  401.     // traccia le parti orizzontali dei crocini
  402.     for( i=0; i<=gNVCas; ++i ) {
  403.         y1 = y2 = iY + ((REAL)i)*hCas;
  404.         for( j=0; j<=gNOCas; ++j ) {
  405.             x1 = iX + ((REAL)(j*wCas)) - kRCrocino;
  406.             x2 = iX + ((REAL)(j*wCas)) + kRCrocino;
  407.             gfx->DrawLine( &penna, x1, y1, x2, y2 );
  408.         }
  409.     }
  410.  
  411.     // traccia il testo, se necessario
  412.     if( *gTCas != '\0' ) {
  413.         if( gNum ) { l = strlen( gTCas ); n = 1; }
  414.  
  415.         for( i=0; i<gNVCas; ++i ) {
  416.             rf.Y = iY + ((REAL)i)*hCas;
  417.  
  418.             for( j=0; j<gNOCas; ++j ) {
  419.                 rf.X = iX + ((REAL)(j*wCas));
  420.                 if( gNum ) wsprintf( gTCas+l, " (%d)", n++ );
  421.                 gfx->DrawString( CharStr2WCharStr(gTCas), -1, &font, rf, &sf, &nero );
  422.             }
  423.         }
  424.  
  425.         if( gNum ) gTCas[l] = '\0';
  426.     }
  427. }
  428.  
  429. /*==============================================================================
  430. Copia nel device context passato tramite il parametro hdc il contenuto della
  431. immagine gBmp.
  432. ==============================================================================*/
  433.  
  434. void TracciaAnteprima( HDC hdc ) {
  435.     Graphics gfxWnd( hdc );
  436.     if( gfxWnd.GetLastStatus() != Ok ) return;
  437.  
  438.     Pen penna( 0xFF000000, 2 );
  439.     RectF rAux( gRAp.left, gRAp.top, gRAp.right-gRAp.left, gRAp.bottom-gRAp.top );
  440.     gfxWnd.DrawImage( gBmp, rAux );
  441.     rAux.Inflate( 2, 2 );
  442.     gfxWnd.DrawRectangle( &penna, rAux );
  443. }
  444.  
  445.  
  446. /*==============================================================================
  447. Questa funzione e' stata copiata e incollata dalla documentazione di GDI+.
  448. ==============================================================================*/
  449.  
  450. int GetEncoderClsid( const WCHAR* format, CLSID* pClsid ) {
  451.    UINT  num = 0;          // number of image encoders
  452.    UINT  size = 0;         // size of the image encoder array in bytes
  453.  
  454.    ImageCodecInfo* pImageCodecInfo = NULL;
  455.  
  456.    GetImageEncodersSize(&num, &size);
  457.    if(size == 0)
  458.       return -1;  // Failure
  459.  
  460.    pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
  461.    if(pImageCodecInfo == NULL)
  462.       return -1;  // Failure
  463.  
  464.    GetImageEncoders(num, size, pImageCodecInfo);
  465.  
  466.    for(UINT j = 0; j < num; ++j)
  467.    {
  468.       if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
  469.       {
  470.          *pClsid = pImageCodecInfo[j].Clsid;
  471.          free(pImageCodecInfo);
  472.          return j;  // Success
  473.       }
  474.    }
  475.  
  476.    free(pImageCodecInfo);
  477.    return -1;  // Failure
  478. }
  479.  
  480.  
  481. /*==============================================================================
  482. Registra l'immagine gBmp nel file chiamato kStrNomeFile.
  483. ==============================================================================*/
  484.  
  485. bool SalvaImmagine( HWND hwnd ) {
  486.     CLSID  cls;
  487.     bool classeTrovata;
  488.     bool imgSalvata;
  489.  
  490.     classeTrovata = GetEncoderClsid(L"image/png",&cls) > -1;
  491.  
  492.     if( classeTrovata ) {
  493.         imgSalvata = gBmp->Save(kStrNomeFile,&cls,NULL) == Ok;
  494.         if( imgSalvata )
  495.             Info( kStrSalvataggioOk, hwnd );
  496.         else Errore( kStrSalvataggioFallito );
  497.         return imgSalvata;
  498.     }
  499.     else {
  500.         Errore( kStrSalvataggioFallito );
  501.         return classeTrovata;
  502.     }
  503. }
  504.  
  505. /*==============================================================================
  506. Mostra un message box per segnalare all'utente l'informazione descritta nella
  507. stringa passata tramite il parametro msg.
  508. ==============================================================================*/
  509.  
  510. void Info( const char *msg, HWND hwnd ) {
  511.     if( msg == NULL ) return;
  512.     MessageBox( hwnd, msg, kStrNomeProgramma, MB_OK|MB_ICONINFORMATION );
  513. }
  514.  
  515. /*==============================================================================
  516. Mostra un message box per avvisare l'utente che s'e' verificato l'errore
  517. descritto nella stringa passata tramite il parametro msg.
  518. ==============================================================================*/
  519.  
  520. void Errore( const char *msg, HWND hwnd ) {
  521.     if( msg == NULL ) msg = kStrErrIndefinito;
  522.     MessageBox( hwnd, msg, kStrNomeProgramma, MB_OK|MB_ICONERROR );
  523. }
  524.  
  525.  
  526. // ===> PER GDIPLUS <===========================================================
  527.  
  528. ULONG_PTR gdiplusToken = 0;
  529.  
  530. UINT InizializzaGdiPlus( void ) {
  531.     GdiplusStartupInput gdiplusStartupInput;
  532.     return GdiplusStartup( &gdiplusToken, &gdiplusStartupInput, NULL ) == Ok;
  533. }
  534.  
  535. void DismettiGdiPlus( void ) {
  536.     GdiplusShutdown( gdiplusToken );
  537. }