Source Code Commentary

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

Initializing QISLIB

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

Getting the GDSII File Name

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



ARTWORK CONVERSION SOFTWARE, INC.                  Company Profile
417 Ingalls St.,     Santa Cruz, CA 95060         Tel (831) 426-6163     Fax 426-2824               email: info@artwork.com