This week I decided to get started on the QR Code Plugin of the Month I mentioned in this previous post, and show a few interesting techniques along the way. The introductory post mentioned a few different approaches for creating/embedding the codes in a drawing. For now – as it’s by far the simplest – I’ve chosen to insert the code as a raster image. In this post we’ll show how to define and insert a raster image of a QR Code into the drawing – for now one with a hardcoded message string, placed at the origin – and we’ve evolve the code over a couple of different posts to provide more control over the contents and placement, first by using selection functions and then by implementing a jig.
At some point I’ll have to implement some kind of user interface for defining QR Codes: I’ll probably take inspiration for that from the ZXing QR Code Generator.
Here’s the C# code for this initial implementation, much of which was based on this DevNote on the ADN site:
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
namespace QRCodeApplication
{
public class Commands
{
[CommandMethod("QR")]
static public void QRCode()
{
// Base record name and URL constants
const string recBase = "ADNP_QR";
const string rootUrl =
"http://chart.apis.google.com/chart?cht=qr&chs=500x500&chl=";
// Hardcode our message, for now
string message = "mailto%3Akean.walmsley%40autodesk.com";
Document doc =
Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Transaction tr =
doc.TransactionManager.StartTransaction();
using (tr)
{
ObjectId dictId =
RasterImageDef.GetImageDictionary(db);
if (dictId.IsNull)
{
// Image dictionary doesn't exist, create new
dictId =
RasterImageDef.CreateImageDictionary(db);
}
// Open the image dictionary
DBDictionary dict =
(DBDictionary)tr.GetObject(
dictId,
OpenMode.ForRead
);
// Get a unique record name for our raster image
// definition
int i = 0;
string recName = recBase + i.ToString();
while (dict.Contains(recName))
{
i++;
recName = recBase + i.ToString();
}
RasterImageDef rid = new RasterImageDef();
// Set its source image
rid.SourceFileName = rootUrl + message;
// Load it
rid.Load();
dict.UpgradeOpen();
ObjectId defId = dict.SetAt(recName, rid);
// Let the transaction know
tr.AddNewlyCreatedDBObject(rid, true);
// Create the raster image that references the
// definition
RasterImage ri = new RasterImage();
ri.ImageDefId = defId;
ri.ShowImage = true;
// Just place the image at the origin in a unit square
ri.Orientation =
new CoordinateSystem3d(
Point3d.Origin,
new Vector3d(1, 0, 0),
new Vector3d(0, 1, 0)
);
BlockTable bt =
(BlockTable)tr.GetObject(
db.BlockTableId,
OpenMode.ForRead
);
BlockTableRecord btr =
(BlockTableRecord)tr.GetObject(
bt[BlockTableRecord.ModelSpace],
OpenMode.ForWrite
);
btr.AppendEntity(ri);
tr.AddNewlyCreatedDBObject(ri, true);
// Create a reactor between the RasterImage and the
// RasterImageDef to avoid the "unreferenced"
// warning in the XRef palette
RasterImage.EnableReactors(true);
ri.AssociateRasterDef(rid);
tr.Commit();
}
}
}
}
Here are the results of running the QR command:
In the next post we’ll provide a simple, command-line based UI for the message to be encoded (probably still an email address, for now) as well as letting the user select the location of the attached image. This is actually more interesting than it sounds, as we’ll implement some logic to keep the image in this orientation irrespective of the order in which the corners are selected. But more on that in due course.