Tuesday, August 31, 2010

Converting dbf to csv with Python

I wanted something in the ArcGIS toolbox that I could use to convert a dbf to a csv. I didn't see anything already there, and the scripts I found in the ESRI forums seemed needlessly complicated, so I wrote this little one and added it as a new script tool with two inputs of type File. The first one is an Input and is the dbf filename. The second one is an Output and is the csv filename.

This script uses the dbfpy module from http://dbfpy.sourceforge.net/.

import csv
from dbfpy import dbf
import sys

dbf_fn = sys.argv[1]
csv_fn = sys.argv[2]

in_db = dbf.Dbf(dbf_fn)
out_csv = csv.writer(open(csv_fn, 'wb'))

names = []
for field in in_db.header.fields:
    names.append(field.name)
out_csv.writerow(names)

for rec in in_db:
    out_csv.writerow(rec.fieldData)

in_db.close()

Thursday, August 12, 2010

Smoother Pyramid Layers

So yesterday I was working with a couple of 1-band raster images. The original images looked fine but my processed ones looked pixelated when zoomed out.


The problem was that the pyramid layers were built using nearest neighbor (the default). I didn't see where to change that in ArcMap or IMAGINE right away, so I solved the problem with gdaladdo.

gdaladdo --config HFA_USE_RRD YES -r average all_utm.img 4 8 16 32 64 128 256 512

I later found the correct settings in ArcMap 10, but still have no idea where they are in IMAGINE 2010.

Pyramid options are in the Environment Settings in ArcMap 10

And here's what my final output looks like:

Friday, August 6, 2010

Creating an installer for a COM component for ArcGIS 10

I just wrote my first installer for an ArcGIS 10 COM component. I realize that ESRI has created this new thing called an add-in, but since I want my component to work with both 9.3 and 10, I figured it would be easiest to keep most things the same. So I built my base project, fired up ArcGIS 10, and my toolbar was right where I expected it to be. Then I built a setup program using the 9.3 instructions on the ESRI website. I built the setup program, ran it, started ArcGIS, and my toolbar was nowhere to be found. Hmmm....

Turns out that with version 10, ESRI decided not to use the regular Windows COM registration services and instead uses its own registration utility. This utility can be used to register COM components, or they suggest using the Add From File option on the Customize dialog in ArcMap. I didn't like that solution because that's asking a bit too much for some of our users (don't ask what they're doing using ArcMap!). I want them to just double-click a file icon.

So here's how I created my installer for ArcGIS 10:
  1. Open the solution that you want to create an installer for.
  2. Add an Installer Class to the project that you want to create the installer for.
  3. Add the following code to the new Installer class. Note that you may want to enclose things in try/catch blocks. I have it show an error message if it takes more than 5 seconds to unregister the component.
public override void Install(System.Collections.IDictionary stateSaver)
{
    base.Install(stateSaver);
    string esriRegAsmFilename = Path.Combine(
        Environment.GetFolderPath(Environment.SpecialFolder.CommonProgramFiles),
        "ArcGIS\\bin\\ESRIRegAsm.exe");
    Process esriRegAsm = new Process();
    esriRegAsm.StartInfo.FileName = esriRegAsmFilename;
    esriRegAsm.StartInfo.Arguments =
        string.Format("\"{0}\" /p:Desktop", base.GetType().Assembly.Location);
    esriRegAsm.Start();
}

public override void Uninstall(System.Collections.IDictionary savedState)
{
    base.Uninstall(savedState);
    string esriRegAsmFilename = Path.Combine(
        Environment.GetFolderPath(Environment.SpecialFolder.CommonProgramFiles),
        "ArcGIS\\bin\\ESRIRegAsm.exe");
    Process esriRegAsm = new Process();
    esriRegAsm.StartInfo.FileName = esriRegAsmFilename;
    esriRegAsm.StartInfo.Arguments =
        string.Format("\"{0}\" /p:Desktop /u", base.GetType().Assembly.Location);
    esriRegAsm.Start();
    if (!esriRegAsm.WaitForExit(5000))
        MessageBox.Show("ESRI unregistration failed");
}
  1. Make sure the Specific Version property for the referenced assemblies in the project is set to False and rebuild the project.
  2. Add a Setup Project to your solution.
  3. Right-click the new Setup project in Solution Explorer and select Add | Project Output... 
  4. In the dialog box, select the project you want to deploy from the pulldown menu and then select Primary output and click OK.
  5. This will generate a list of detected dependencies. Right-click and exclude all of the ESRI assembles and stdole.dll.
  6. Open the Properties pane for the .tlb file in the dependency list, and change the Register property to vsdrfDoNotRegister.
  7. Right-click the Setup project in the Solution Explorer and select View | Custom Actions.
  8. In the Custom Actions window, right-click the Install folder and select Add Custom Action...
  9. In the dialog box, select File System on Target Machine from the pulldown menu and then double-click Application Folder.
  10. Double-click Primary output from <AssemblyName>.
  11. Repeat this for the Uninstall folder in the Custom Actions window.
  12. Build the setup project.

Thursday, August 5, 2010

Finding your custom ArcGIS extension with C#

An extension object is handy and logical place to store data when creating a custom component for ArcGIS. However, you need to be able access the extension object from your other objects such as commands. Here's how to do it.

Put something like this in the command's OnCreate() method (not in the constructor, especially if you're using a just-in-time extension, because the extension may not be loaded yet when the command is constructed):

UID uid = new UIDClass();
uid.Value = "MyNamespace.MyJITExtension";
m_extension = (MyJITExtension)m_application.FindExtensionByCLSID(uid);

The above method worked fine for me with ArcGIS 9.3 and Visual Studio 2008. I came across the following error when using ArcGIS 10 and Visual Studio 2010:

Error 4: Interop type 'ESRI.ArcGIS.esriSystem.UIDClass' cannot be embedded. Use the applicable interface instead.

To solve this problem, change the Embed Interop Types property for each referenced ESRI assembly to False. Or don't target .NET Framework 4.0.