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);
}
|