Конвертация изображений из формата RAW в JPEG

Общие вопросы, не зависящие от языка реализации.

Модераторы: Duncon, Hawk, Romeo, Eugie

Ответить
Аватара пользователя
Decoder
Сообщения: 303
Зарегистрирован: 19 фев 2008, 23:11
Откуда: Moscow

10 июн 2014, 12:12

Всем привет. Сможет ли кто подсказать, как мне в своей программе сконвертировать файлы изображений оригинальных RAW-форматов цифровых камер Canon, Nikon, Sony и др. в обычный формат типа JPEG? Желательно чтобы можно было ещё задавать размер изображения на выходе.
Поумнеть несложно, куда труднее от дури избавиться.
Аватара пользователя
somewhere
Сообщения: 1837
Зарегистрирован: 31 авг 2006, 17:14
Откуда: 71 RUS
Контактная информация:

10 июн 2014, 14:23

Различия RAW формата камер разных производителей настолько велики, что единой спецификации не существует. Даже не залезая в гугл я могу по пальцам сосчитать с десяток различных спецификаций RAW, хотя по факту их намного больше. Компания Adobe предложила производителям единый формат DNG, но пока что поддержка этого формата наблюдается у 5-7 фотиков. Если "своя программа" не является конвертером графических файлов, то писать собственные фильтры - не к чему. Стоит воспользоваться технологией плагинов для любого более-менее популярного редактора или вьювера. Как правило плагин - это DLL с парой/тройкой экспортируемых функций, служащих для перевода данных из одного формата в другой. Подключив их к своей программе и зная декларацию этих функций можно получить полноценную конвертацию
It's a long way to the top if you wanna rock'n'roll
Аватара пользователя
WinMain
Сообщения: 913
Зарегистрирован: 14 янв 2005, 10:30
Откуда: Москва
Контактная информация:

10 июн 2014, 22:06

Это можно сделать достаточно легко с помощью системного интерфейса ITranscodeImage и нескольких вспомогательных функций Shell API. Данный интерфейс имеет метод
TranscodeImage, у которого на выходе будет изображение в формате Bitmap или JPEG. На входе у него может быть любой файл графического формата, который поддерживается Windows. Что же касается RAW-файлов с цифровых фотокамер, то для них нужно устанавливать специальный пакет кодеков, он так и называется: Microsoft camera codec pack http://www.microsoft.com/ru-ru/download ... x?id=26829
Скачиваешь его, устанавливаешь и Windows после этого сможет работать с данными форматами файлов. Для Windows 8 ничего дополнительно устанавливать не нужно, там эти компоненты уже присутствуют.

Аватара пользователя
Decoder
Сообщения: 303
Зарегистрирован: 19 фев 2008, 23:11
Откуда: Moscow

11 июн 2014, 09:21

Дистрибутив с кодеками я скачал, установил. Теперь изображения с фотокамер просматриваются штатными просмотрщиками Windows и в файловом проводнике отображаются в виде миниатюрных картинок. А вот как мне теперь их сконвертировать в JPEG? Имеется ли какой-нибудь простой пример использования интерфейса ITranscodeImage для преобразования картинок?
Поумнеть несложно, куда труднее от дури избавиться.
Аватара пользователя
somewhere
Сообщения: 1837
Зарегистрирован: 31 авг 2006, 17:14
Откуда: 71 RUS
Контактная информация:

11 июн 2014, 09:56

Дистрибутив с кодеками я скачал, установил
Тогда уж не забудь распространять его в составе своей программы.
Имеется ли какой-нибудь простой пример использования интерфейса ITranscodeImage для преобразования картинок?
Что-то не нашел. Стоит подумать о целесообразности использования метода, который не используют другие программисты. Особенно, если от пользователя потребуется установка дополнительных компонент. Будет проще использовать LibRaw (http://www.libraw.su).
It's a long way to the top if you wanna rock'n'roll
Аватара пользователя
WinMain
Сообщения: 913
Зарегистрирован: 14 янв 2005, 10:30
Откуда: Москва
Контактная информация:

11 июн 2014, 12:41

Могу предложить уже готовый вариант функции с использованием этого интерфейса.

Код: Выделить всё

#include "stdafx.h"
#include <Shlobj.h>
#include <ImageTranscode.h>

HRESULT TranscodeImage(LPCTSTR szFileIn, LPCTSTR szFileOut, UINT uiWidth, UINT uiHeight)
{
	// Полный путь к файлу...
	TCHAR szFullPath[MAX_PATH] = _T("");
	::GetFullPathName(szFileIn, _countof(szFullPath), szFullPath, NULL);
	// Создание ShellItem
	HRESULT hr  = E_INVALIDARG;
	CComPtr<IShellItem> pShellItem;
	hr = ::SHCreateItemFromParsingName(szFullPath, NULL, IID_IShellItem, (LPVOID*)&pShellItem);
	if (pShellItem != NULL)
	{
		// Удаление существующего файла
		if (::PathFileExists(szFileOut))
		{
			: :D eleteFile(szFileOut);
		}
		// Поток записи данных...
		CComPtr<IStream> pStream;
		hr = ::SHCreateStreamOnFileEx(szFileOut, STGM_WRITE, 0, TRUE, NULL, &pStream);
		if (pStream != NULL)
		{
			// Транскодинг изображения...
			CComPtr<ITranscodeImage> pTranscoder;
			hr = pTranscoder.CoCreateInstance(__uuidof(ImageTranscode)); 
			if (pTranscoder != NULL)
			{
				hr = pTranscoder->TranscodeImage(pShellItem, uiWidth, uiHeight, TI_JPEG, pStream, NULL, NULL);
			}
		}
	}

	return hr;
}

В параметры функции передаёшь имя входного файла, потом имя выходного файла, максимальную ширину и максимальную высоту изображения. При масштабировании картинки сохраняются её пропорции.
Поскольку функция использует СОМ-интерфейсы, то в клиентском приложении нужно будет вызвать функции CoInitialize() и CoUninitialize(); Вот примерно так...

Код: Выделить всё

struct CO_INITIALIZE
{
	CO_INITIALIZE()
	{
		::CoInitialize(NULL);
	}
	~CO_INITIALIZE()
	{
		::CoUninitialize();
	}
} co_init;

int _tmain(int argc, _TCHAR* argv[])
{
	LPCTSTR szInputFile = _T("IMG_1234.NEF"); // Камера NIKON

	// Перекодирование изображения...
	HRESULT hr = TranscodeImage(szInputFile, _T("output.jpg"), 1200, 800);
	if (SUCCEEDED(hr))
	{
		_tcprintf(_T("%s\n"), _T("Завершено успешно."));
	} else
	{
		_tcprintf(_T("%s\n"), _T("Возникла ошибка."));
	}

	_gettch();

	return 0;
}



Входные параметры функции в данном примере я захардкодил для наглядности, но в реальном проекте можешь получать их из командной строки через параметры argv[1], argv[2], и т.д.
Аватара пользователя
somewhere
Сообщения: 1837
Зарегистрирован: 31 авг 2006, 17:14
Откуда: 71 RUS
Контактная информация:

11 июн 2014, 13:41

Вот не пойму, зачем нужно было в TranscodeImage делать ShellItem, а не Stream? При том, что вывод идет в Stream - в чем логика?
It's a long way to the top if you wanna rock'n'roll
Аватара пользователя
Decoder
Сообщения: 303
Зарегистрирован: 19 фев 2008, 23:11
Откуда: Moscow

11 июн 2014, 15:11

А ведь и правда всё отлично работает!
Одна небольшая функция, набор кодеков - и вот тебе готовый конвертор.
WinMain, спасибо огромное!
Поумнеть несложно, куда труднее от дури избавиться.
Аватара пользователя
WinMain
Сообщения: 913
Зарегистрирован: 14 янв 2005, 10:30
Откуда: Москва
Контактная информация:

11 июн 2014, 22:19

somewhere писал(а):Вот не пойму, зачем нужно было в TranscodeImage делать ShellItem, а не Stream? При том, что вывод идет в Stream - в чем логика?
Через IStream на входе можно получить лишь поток бинарных данных из файла, но при этом не будет никакой информации о том, что это за файл и как с ним работать.
Вся сопутствующая информация о типе данного файла (определяется по расширению файла) содержится в системном реестре. Там же содержится информация и о том, какие программные компоненты нужны для работы с данным типом файла. Ну а для сохранения в файл перекодированного изображения требуется только открытый на запись файловый поток и ничего больше.
Ответить