Source Code CommentaryWhen you download and install QISLIB it comes with TiffExtract and the Visual C project files needed to build it. Below we add some comments and explanations that highlight important aspects of using QISLIB We start with the usual includes and code needed for our simple window. Click here to jump to where QISLIB is initialized. // tiffextractDlg.cpp : implementation file // #include "stdafx.h" #include "tiffextract.h" #include "tiffextractDlg.h" #include "qislib.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CAboutDlg dialog used for App About class CAboutDlg : public CDialog { public: CAboutDlg(); // Dialog Data //{{AFX_DATA(CAboutDlg) enum { IDD = IDD_ABOUTBOX }; //}}AFX_DATA // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CAboutDlg) protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL // Implementation protected: //{{AFX_MSG(CAboutDlg) //}}AFX_MSG DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) { //{{AFX_DATA_INIT(CAboutDlg) //}}AFX_DATA_INIT } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CAboutDlg) //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) //{{AFX_MSG_MAP(CAboutDlg) // No message handlers //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CTiffextractDlg dialog CTiffextractDlg::CTiffextractDlg(CWnd* pParent /*=NULL*/) : CDialog(CTiffextractDlg::IDD, pParent) { //{{AFX_DATA_INIT(CTiffextractDlg) m_gdsiifile = _T(""); m_coordsfile = _T(""); m_layernumstr = _T(""); //}}AFX_DATA_INIT // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); GDSIIOpened = false; GDSIIFile[0] = 0; CoordsFile[0] = 0; } void CTiffextractDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CTiffextractDlg) DDX_Text(pDX, IDC_GDSLBL, m_gdsiifile); DDX_Text(pDX, IDC_COORDSLBL, m_coordsfile); DDX_Text(pDX, IDC_LAYEREDIT, m_layernumstr); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CTiffextractDlg, CDialog) //{{AFX_MSG_MAP(CTiffextractDlg) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_OPENGDSBUT, OnOpengdsbut) ON_BN_CLICKED(IDC_COORDSBUT, OnCoordsbut) //}}AFX_MSG_MAP ON_EN_CHANGE(IDC_LAYEREDIT, &CTiffextractDlg::OnEnChangeLayeredit) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CTiffextractDlg message handlers BOOL CTiffextractDlg::OnInitDialog() { CDialog::OnInitDialog(); // Add "About..." menu item to system menu. // IDM_ABOUTBOX must be in the system command range. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon // TODO: Add extra initialization here char tempfullfn[_MAX_PATH]; char tempfullfn2[_MAX_PATH]; char *aslash; if (GetModuleFileName(AfxGetInstanceHandle(),tempfullfn,sizeof(tempfullfn)) != 0) { aslash = strrchr(tempfullfn,'\\'); if (aslash != NULL) *aslash = 0; } else { strcpy(tempfullfn2,GetCommandLine()); aslash = strrchr(tempfullfn2,'\\'); if (aslash != NULL) *aslash = 0; if (tempfullfn2[0] == '"') strcpy(tempfullfn,&tempfullfn2[1]); else strcpy(tempfullfn,tempfullfn2); } Just below QISLIB is initialized. Click here to jump to where the layer list is entered. int ret = QisLib_InitLib(tempfullfn); char tempstr[256]; if (ret != 0) { sprintf(tempstr,"Error occurred when initializing QIS Library (%d).",ret); AfxMessageBox(tempstr); } GetDlgItem(IDC_OPENGDSBUT)->EnableWindow(FALSE); GetDlgItem(IDC_COORDSBUT)->EnableWindow(FALSE); GetDlgItem(IDOK)->EnableWindow(FALSE); return TRUE; // return TRUE unless you set the focus to a control } void CTiffextractDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialog::OnSysCommand(nID, lParam); } } // If you add a minimize button to your dialog, you will need the code below // to draw the icon. For MFC applications using the document/view model, // this is automatically done for you by the framework. void CTiffextractDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // device context for painting SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); // Center icon in client rectangle int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // Draw the icon dc.DrawIcon(x, y, m_hIcon); } else { CDialog::OnPaint(); } } // The system calls this to obtain the cursor to display while the user drags // the minimized window. HCURSOR CTiffextractDlg::OnQueryDragIcon() { return (HCURSOR) m_hIcon; } Getting the Layer List The list of layers we wish to rasterize has to be read from the dialog box's field and parsed. This will be passed to QISLIB before the GDSII file is opened to set the InputLayerFilter so that only the layer(s) we are processing will get loaded into memory. Click here to jump to where we get the GDSII file name and start setting up QISLIB. char* GetLayerSelection(char *laystr, CString layernumstr) { char **layer_list; char *tempstr; char tstr[64]; int i, n; char *cp; tempstr = (char *) malloc(strlen(LPCTSTR(layernumstr))+1); strcpy(tempstr,LPCTSTR(layernumstr)); n = 0; cp = strtok(tempstr," \t,"); while(cp != NULL) { n++; cp = strtok(NULL," \t,"); } layer_list = (char **) malloc(sizeof(char *) * n); strcpy(tempstr,LPCTSTR(layernumstr)); n = 0; cp = strtok(tempstr," \t,"); while(cp != NULL) { layer_list[n] = cp; n++; cp = strtok(NULL," \t,"); } // layernum = atoi(LPCTSTR(layernumstr)); // turn off All layers, open only the specified layer (can be changed to open multiple layers) // sprintf(laystr,"All-NULL,%d-%d",layernum,layernum); strcpy(laystr,"All-NULL"); for(i = 0; i < n; i++) { sprintf(tstr,",%s-%s",layer_list[i],layer_list[i]); strcat(laystr,tstr); } free(layer_list); free(tempstr); return(laystr); } Here we get the name/path of the GDSII file from the file browser dialog. Click here to jump to where we set some QISLIB parameters prior to actually opening the file with QISLIB. void CTiffextractDlg::OnOpengdsbut() { // TODO: Add your control notification handler code here CFileDialog filedlg(true,NULL,NULL,OFN_FILEMUSTEXIST); char tempstr[256]; char laystr[256]; int ret; UpdateData(TRUE); if (filedlg.DoModal() == IDOK) { strcpy(GDSIIFile,filedlg.GetPathName()); m_gdsiifile.Format("Opening..."); UpdateData(FALSE); Settings for QISLIB prior to Opening the GDSII File We will set our input layer filter to the layers the user provided. We'll also set LoadMemory ON and Loading of Text to OFF and Array Mode to FULL. Now we are ready to actually open the GDSII file ... Click here to jump to where we open the GDSII file. if (m_layernumstr.GetLength() > 0) { GetLayerSelection(laystr,m_layernumstr); QisLib_SetInputLayerMap(laystr); } else QisLib_SetInputLayerMap("Off"); // turn off layer mapping means open all layers // use more memory to open the GDSII file, operations will be faster QisLib_SetLoadMemory(_QIS_ON); QisLib_SetTextMode(_QIS_OFF); //QisLib_SetStructureDisplayFilterSize(0); // this control should not matter to QisLib_GetHiresImage // but added for completeness //QisLib_SetDisplayFilterSize(0); // this control should not matter to QisLib_GetHiresImage // but added for completeness //QisLib_SetNestingLevel(_QISNL_ALL); // this control should not matter to QisLib_GetHiresImage // but added for completeness QisLib_SetArrayMode(_QISARR_FULL); // on the otherhand this control *IS* VERY important Opening the GDSII File We previously read the GDSII file name and path, we've made the correct settings. Now we can open the file. Click here to jump to the section where the window list is selected by the user ... // open the GDSII file, this might take a while depending on file size ret = QisLib_OpenGDSII(GDSIIFile); if (ret != 0) { GDSIIOpened = false; m_gdsiifile.Format(""); sprintf(tempstr,"Error occurred when opening GDSII file (%d).",ret); AfxMessageBox(tempstr); } else { m_gdsiifile.Format("'%s' opened",GDSIIFile); GDSIIOpened = true; GetDlgItem(IDC_COORDSBUT)->EnableWindow(TRUE); } UpdateData(FALSE); } } Getting the file containing the list of windows The lines below enable the user to pick a file containing the window list. Click here to jump to the loop where we process each line of the window file ... void CTiffextractDlg::OnCoordsbut() { // TODO: Add your control notification handler code here CFileDialog filedlg(true,NULL,NULL,OFN_FILEMUSTEXIST); char tempstr[256]; int ret; if (filedlg.DoModal() == IDOK) { strcpy(CoordsFile,filedlg.GetPathName()); m_coordsfile.Format("%s",CoordsFile); GetDlgItem(IDOK)->EnableWindow(TRUE); UpdateData(FALSE); } } void CTiffextractDlg::OnOK() { // TODO: Add extra validation here //CDialog::OnOK(); if (!GDSIIOpened || CoordsFile[0] == 0) { AfxMessageBox("Open a GDSII file and select a coordinates file first before translating."); return; } LARGE_INTEGER m_startValue; LARGE_INTEGER m_stopValue; LARGE_INTEGER m_frequency; LONGLONG pInterval; bool gottime=false; char outputfn[_MAX_PATH]; char tempstr[256]; char buff[512]; char llurstr[256]; char *cp; double llx,lly,urx,ury,awidth; int widthpixels; int dpinum; int ret; int someerrors = 0; int translatedtiffs = 0; CQisWindow awin; FILE *f=fopen(CoordsFile,"r+t"); if (f == NULL) { sprintf(tempstr,"Error occurred when opening the coordinates file."); AfxMessageBox(tempstr); return; } // start timer if(QueryPerformanceFrequency(&m_frequency)) { if(QueryPerformanceCounter(&m_startValue)) { gottime = true; } } Parsing the Window File, line by line Now we enter a loop. We will parse a line from the file and, assuming there are no problems in the line, pass the extraction window and request a hires TIFF image to be written to a file. Here is what a proper line should look like: 50,50,550,550 1000,1000 TIFF c:/tmp/GdsData/CawTestOut/0_0.tif Click here to jump to the location in the code where the QISLIB window is defined and the hi-res tiff is requested. // translate to tiff for each line in the coordinates file do { if (fgets(buff,512,f) == NULL) break; cp = strrchr(buff,'\n'); if (cp != NULL) *cp = 0; cp = strtok(buff," "); if (cp != NULL) { // first parameter is lower left and upper right strcpy(llurstr,cp); } else continue; // not enough parameters, skip this line cp = strtok(NULL," "); if (cp != NULL) { // second parameter is pixels,pixels, only use width pixels value // no support for different DPI for width and height // only used for Tiff, not for GDS (but a placeholder number must still exist) widthpixels = atoi(cp); } else continue; // not enough parameters, skip this line cp = strtok(NULL," "); if (cp != NULL) { // third parameter is GDS or TIFF // only supports TIFF for now, so ignore this parameter if (stricmp(cp,"tiff") == 0) FormatTiffOrGDS = 1; else if (stricmp(cp,"gds") == 0) FormatTiffOrGDS = 2; else continue; // unknown, do nothing } else continue; // not enough parameters, skip this line cp = strtok(NULL," "); if (cp != NULL) { // fourth parameter is output file name strcpy(outputfn,cp); } else continue; // not enough parameters, skip this line // get the lower left and upper right coordinates cp = strtok(llurstr,","); if (cp != NULL) { llx = atof(cp); cp = strtok(NULL,","); if (cp != NULL) { lly = atof(cp); cp = strtok(NULL,","); if (cp != NULL) { urx = atof(cp); cp = strtok(NULL,","); if (cp != NULL) { ury = atof(cp); } else continue; // not enough parameters, skip this line } else continue; // not enough parameters, skip this line } else continue; // not enough parameters, skip this line } else continue; // not enough parameters, skip this line // assuming is that file unit is um awidth = urx - llx; dpinum = (int)((((double)widthpixels) / (awidth / 25400.0)) + 0.5); // translate 1 window awin.MinX.UserUnits = llx; awin.MinY.UserUnits = lly; awin.MaxX.UserUnits = urx; awin.MaxY.UserUnits = ury; Setting Window and Requesting Hi-Res Tiff Image Output Here we make the actual calls to the library - first to set the window and then to direct QISLIB to produce a high res TIFF output and write it to disk. QisLib_SetExactWindow(awin); if (FormatTiffOrGDS == 1) ret = QisLib_GetHiresImage(dpinum,outputfn); else if (FormatTiffOrGDS == 2) ret = QisLib_GetGDSII(outputfn); if (ret != 0) someerrors = ret; else translatedtiffs++; } while(1); Timing Info Our loop is completed and the timer that we started just before the loop is stopped. The time in the loop is reported. // stop timer if (gottime) { QueryPerformanceCounter(&m_stopValue); pInterval = m_stopValue.QuadPart - m_startValue.QuadPart; pInterval = (pInterval*1000)/(m_frequency.QuadPart); // milliseconds sprintf(tempstr,"Successfully translated %d TIFF/GDS files in %I64d milliseconds",translatedtiffs,pInterval); AfxMessageBox(tempstr); } fclose(f); if (someerrors != 0) { sprintf(tempstr,"Error occurred when translating 1 or more TIFF/GDS file. Last error code %d.",someerrors); AfxMessageBox(tempstr); } } Clean Up Now that we are done with our extractions we close QISLIB. void CTiffextractDlg::OnCancel() { // TODO: Add extra cleanup here QisLib_CloseLib(); CDialog::OnCancel(); } void CTiffextractDlg::OnEnChangeLayeredit() { GetDlgItem(IDC_OPENGDSBUT)->EnableWindow(TRUE); } |