Дело в том, что потребовалось получать и обрабатывать несколько снимков за раз. Я думал обойтись штатным OpenFileDialog. Ведь цифровая камера, будучи подключенной по USB к компьютеру, притворяется обычной папкой. Но, оказалось, "папка" эта не совсем обычная. В частности, например, при попытке доступа к изображению система создает его копию во временных файлах, и позволяет работать уже с этой копией. Если же выбрать несколько изображений, то OpenFileDialog вернёт вместо путей что-то маловразумительное типа "004\Root\IMG_1111" "004\Root\IMG_1112" "004\Root\IMG_1113".
Поэтому возникла мысль использовать обходной путь. В Windows есть нечто под названием Windows Image Acquisition. Статус этой технологии мне остался до конца неясным - то ли она уже устарела, то ли еще нет - но и в XP, и в 7 эта штука присутствует, хоть и двух разных версий.
Сначала попытался использовать WIA первой версии. Думал, обратная совместимость вывезет. Работаю я на WinXP, там WIA 1.0, что называется, "из коробки". Итак, добавляю в проект ссылку на Microsoft Windows Image Acquisition 1.01 Type Library (Add Reference, вкладка COM), получаю пространство имен WIALib и в нем кучку классов, с которыми уже можно работать:
using WIALib;
...
private void button1_Click(object sender, EventArgs e)
{
object selectUsingUI = System.Reflection.Missing.Value;
try
{
// создаем класс для работы с WIA
WiaClass wiamanager = new WiaClass();
// выводим диалог выбора цифровой камеры
ItemClass wiaRoot = (ItemClass)wiamanager.Create(ref selectUsingUI);
if (wiaRoot == null)
return;
// выводим диалог выбора изображений, хранящихся в камере
CollectionClass wiaPics = (CollectionClass)wiaRoot.GetItemsFromUI(WiaFlag.UseCommonUI, WiaIntent.ImageTypeColor);
// каждое выбранное изображение копируем в каталог с нашей программой
if (wiaPics != null)
foreach (object wiaObj in wiaPics)
{
ItemClass wiaItem = (ItemClass)Marshal.CreateWrapperOfType(wiaObj, typeof(ItemClass));
string tmpFileName = Path.GetDirectoryName(Application.ExecutablePath) + "\\" + wiaItem.Name;
wiaItem.Transfer(tmpFileName, false);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Всё работает чудесно. Но обнаружились два момента. Первое: без дополнительной обработки изображения получаются чудовищного размера (без всякого сжатия), и второе, самое главное: этот способ не сработал в Windows 7. А именно, при запуске своей программы на Windows 7 64bit я получил такое сообщение об ошибке: Сбой при получении производства объектов класса COM для компонента с CLSID {4EC4272E-2E6F-4EEB-91D0-EBC4D58E8DEE} в результате следующей ошибки: 80040154. В общем, похоже, в современных виндах WIA 1.0 нет.Пришлось обратиться к WIA 2.0. Под Windows XP потребовалось её установить дополнительно. Я брал дистрибутив отсюда: http://vbnet.mvps.org/files/updates/wiaautsdk.zip. Дальше добавляю в проект ссылку на Microsoft Windows Image Acquisition Library v2.0 (всё на той же вкладке COM) и получаю пространство имен WIA. Использовал это примерно так:
using WIA;
...
private void button1_Click(object sender, EventArgs e)
{
// создаем класс для работы с камерой
WIA.CommonDialogClass dlg = null;
try
{
dlg = new WIA.CommonDialogClass();
}
catch(Exception ex)
{
MessageBox.Show("Невозможно подключиться к интерфейсу работы с камерой:\n" + ex.Message, "Ошибка",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
if (dlg == null)
return;
// выбираем камеру
WIA.DeviceClass d = null;
try
{
d = (WIA.DeviceClass)dlg.ShowSelectDevice(WIA.WiaDeviceType.CameraDeviceType, true, false);
}
catch (Exception ex)
{
MessageBox.Show("Невозможно подключиться к камере:\n" + ex.Message, "Ошибка",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
if (d == null)
return;
// выбираем изображения
WIA.Items items = dlg.ShowSelectItems(d, WIA.WiaImageIntent.ColorIntent,
WIA.WiaImageBias.MinimizeSize, false, true, false);
if (items != null)
foreach (WIA.Item item in items)
{
WIA.ImageFile img = (WIA.ImageFile)item.Transfer(WIA.FormatID.wiaFormatJPEG);
// выясняем имя и расширение выбранного изображения
string
tmpFileName = "",
tmpFileExt = "";
foreach (WIA.Property prop in item.Properties)
{
if (prop.Name == "Item Name")
tmpFileName = prop.get_Value().ToString();
if (prop.Name == "Filename extension")
tmpFileExt = prop.get_Value().ToString();
}
if (tmpFileExt == "")
tmpFileExt = img.FileExtension;
if (Path.HasExtension(tmpFileName))
tmpFileExt = "";
// копируем выбранное изображение в каталог с нашей программой
string
tmpFullName = Path.GetDirectoryName(Application.ExecutablePath) + "\\"
+ tmpFileName + ((tmpFileExt != "") ? "." : "") + tmpFileExt;
img.SaveFile(tmpFullName);
}
}
Код получился немного длинее, но это из-за проверок. Основной плюс - помимо того, что эта конструкция сработала и в Windows 7 - возможность сохранять изображения в формате JPEG.Кстати, во втором примере в свойствах изображения есть много интересного. Я себе на память сделал скриншот: