Иногда возникает необходимость конвертировать многостраничный tiff-файл в какой-либо другой формат. Но некоторые программы сканирования создают tiff с ошибками:
- отсутствует тэк Photometric Interpretation, определяющий используемую цветовую модель, подробности ниже;
- первая страница сделана в более низком разрешении, чем остальные
Здесь нам приходит на помощь утилита tiffset, находящаяся в пакете libtiff-tools. Устанавливается этот пакет обычным способом:
# aptitude install libtiff-tools
С помощью утилит tiffdump и tiffinfo мы можем посмотреть информацию о файле, причем tiffdump выдает подробную информацию, содержащую:
- имя поля;
- числовой идентификатор поля;
- тип данных поля;
- count (если кто-нибудь знает, что это такое, напишите, буду очень благодарен);
- значение.
При редактировании нас будут интересовать следующие поля:
262 0x0106 PhotometricInterpretation Используемая цветовая модель.
282 0x011A XResolution Количество пикселей в ResolutionUnit строки.
283 0x011B YResolution Количество пикселей в ResolutionUnit столбца.
Первое поле сканирующие программы зачастую просто пропускают. Программы просмотра изображений используют по умолчанию значение 1, но программы преобразования ругаются на его отсутствие.
XResolution и YResolution - поля, определяющие количество точек на ResolutionUnit, как правило - на дюйм. Часто встречаются многостраничные tiff-файлы, в которых первая страница имеет разрешение 300x300, а все остальные - 96x96. Почему так получается - я не знаю.
Чтобы изменить значение тэга, нужно выполнить следующую команду:
$tiffset -s <идентификатор тэга> <присваимое значение> <имя файла>
Например, чтобы изменить цветовую модель, нужно выполнить следующую команду:
$tiffset -s 262 1 image.tif
Нужно учитывать, что у многостраничных файлов изменение выполняется только для первой страницы, поэтому может понадобиться "разрезать" изображение на отдельные части. Это делается с помощью следующей команды:
$tiffsplit image.tif
При этом в текущей директории создаются файлы xaaa.tif, xaab.tif и др. На всякий случай напомню, что в командах возможно использование шаблонов, то есть изменить значение цветовой модели для всех файлов сразу можно так:
$for file in `ls xaa*.tif`; do tiffset -s 262 1 $file; done
Объединить несколько файлов в один можно с помощью команды tiffcp:
$tiffcp *.tif newfile.tif
Теперь полученный файл можно преобразовать, например, в pdf:
$tiff2pdf newfile.tif > newfile.pdf
В данной команде используется оператор перенаправления вывода ">", так как программа tiff2pdf выводит полученные двоичные данные на стандартный вывод
Здесь размещаются новости из программерской, линуксоидной и других сторон моей жизни.
четверг, 18 ноября 2010 г.
среда, 17 ноября 2010 г.
Задачная задача
Над этой задачей я бился 3 дня :-[
Есть таблица, содержащая дерево меню:
create table menu( id int primary key, -- ID пункта меню
parent int null, -- ID "родителя" (null для пунктов верхнего уровня)
name char(30) ) -- Наименование пункта меню
Разработать сохраненную процедуру, позволяющую получить информацию о данном меню в следующем виде:
Level ID Name
------ ---- ------------------------------------
0 1 Меню 1
1 5 Меню 1.1
1 6 Меню 1.2
2 10 Меню 1.2.1
0 2 Меню 2
0 3 Меню 3
1 8 Меню 3.1
2 12 Меню 3.1.1
2 13 Меню 3.1.2
1 9 Меню 3.2
...
Т.е., пункты меню должны быть отсортированы так, чтобы при их обработке клиентское приложение могло построить меню за "один проход". Каждая следующая запись должна быть либо подпунктом предыдущей (если ее уровень вложенности больше, чем у предыдущей), либо иметь общего родителя с предыдущей записью того же уровня вложенности.
Решение основано на создании суррогатного ключа, представляющего собой конкатенацию (склейку) строковых представлений ключей записей, являющихся "предками" данной записи
Например, для приведенной выше выборки данных ключи будут следующими:
synt id name
----------------------------------
1 1 Меню 1
15 5 Меню 1.1
16 6 Меню 1.2
1610 10 Меню 1.2.1
161011 11 Меню 1.2.1.1
2 2 Меню 2
3 3 Меню 3
38 8 Меню 3.1
3812 12 Меню 3.1.1
3813 13 Меню 3.1.2
39 9 Меню 3.2
Фактически, задача представляет из себя поиск в глубину по дереву. Основная трудность заключалась в том, чтобы решить задачу, не используя рекурсии.
Итак, поехали:
CREATE PROCEDURE MyProc
AS
/* Первым делом создаем временную таблицу, включающую в себя поля
исходной таблицы плюс синтетический ключ и число уровней вложенности*/
CREATE TABLE #temp
(id int NULL,
parent int NULL,
synt varchar(255),
name char(30),
lev int
)
/*
Инициализируем таблицу значениями из имеющейся таблицы menu.
Синтетический ключ изначально представляет собой строковое представление первичного ключа.
*/
INSERT INTO #temp
SELECT id, parent, convert(varchar, id) AS synt, name, 0
FROM menu
WHILE ((SELECT COUNT(parent) FROM #temp) > 0)
BEGIN
/* "Переходим" на родительскую запись */
UPDATE #temp
SET id = parent
/* Изменяем указатель родительской записи */
UPDATE #temp
SET #temp.parent = (SELECT parent FROM menu WHERE menu.id = #temp.parent)
/* Добавляем идентификатор текущей записи к синтетическому ключу */
UPDATE #temp
SET synt = convert(varchar,id) + synt
/* Если мы еще не добрались до конца, увеличиваем уровень вложенности */
UPDATE #temp
SET lev = lev + 1
WHERE (id IS NOT NULL)
END
/* Собственно, выборка данных */
SELECT #temp.lev,menu.id,menu.name
FROM menu, #temp
WHERE menu.name = #temp.name
ORDER BY synt
/* Не забываем убирать за собой! */
DROP TABLE #temp
Есть таблица, содержащая дерево меню:
create table menu( id int primary key, -- ID пункта меню
parent int null, -- ID "родителя" (null для пунктов верхнего уровня)
name char(30) ) -- Наименование пункта меню
Разработать сохраненную процедуру, позволяющую получить информацию о данном меню в следующем виде:
Level ID Name
------ ---- ------------------------------------
0 1 Меню 1
1 5 Меню 1.1
1 6 Меню 1.2
2 10 Меню 1.2.1
0 2 Меню 2
0 3 Меню 3
1 8 Меню 3.1
2 12 Меню 3.1.1
2 13 Меню 3.1.2
1 9 Меню 3.2
...
Т.е., пункты меню должны быть отсортированы так, чтобы при их обработке клиентское приложение могло построить меню за "один проход". Каждая следующая запись должна быть либо подпунктом предыдущей (если ее уровень вложенности больше, чем у предыдущей), либо иметь общего родителя с предыдущей записью того же уровня вложенности.
Решение основано на создании суррогатного ключа, представляющего собой конкатенацию (склейку) строковых представлений ключей записей, являющихся "предками" данной записи
Например, для приведенной выше выборки данных ключи будут следующими:
synt id name
----------------------------------
1 1 Меню 1
15 5 Меню 1.1
16 6 Меню 1.2
1610 10 Меню 1.2.1
161011 11 Меню 1.2.1.1
2 2 Меню 2
3 3 Меню 3
38 8 Меню 3.1
3812 12 Меню 3.1.1
3813 13 Меню 3.1.2
39 9 Меню 3.2
Фактически, задача представляет из себя поиск в глубину по дереву. Основная трудность заключалась в том, чтобы решить задачу, не используя рекурсии.
Итак, поехали:
CREATE PROCEDURE MyProc
AS
/* Первым делом создаем временную таблицу, включающую в себя поля
исходной таблицы плюс синтетический ключ и число уровней вложенности*/
CREATE TABLE #temp
(id int NULL,
parent int NULL,
synt varchar(255),
name char(30),
lev int
)
/*
Инициализируем таблицу значениями из имеющейся таблицы menu.
Синтетический ключ изначально представляет собой строковое представление первичного ключа.
*/
INSERT INTO #temp
SELECT id, parent, convert(varchar, id) AS synt, name, 0
FROM menu
WHILE ((SELECT COUNT(parent) FROM #temp) > 0)
BEGIN
/* "Переходим" на родительскую запись */
UPDATE #temp
SET id = parent
/* Изменяем указатель родительской записи */
UPDATE #temp
SET #temp.parent = (SELECT parent FROM menu WHERE menu.id = #temp.parent)
/* Добавляем идентификатор текущей записи к синтетическому ключу */
UPDATE #temp
SET synt = convert(varchar,id) + synt
/* Если мы еще не добрались до конца, увеличиваем уровень вложенности */
UPDATE #temp
SET lev = lev + 1
WHERE (id IS NOT NULL)
END
/* Собственно, выборка данных */
SELECT #temp.lev,menu.id,menu.name
FROM menu, #temp
WHERE menu.name = #temp.name
ORDER BY synt
/* Не забываем убирать за собой! */
DROP TABLE #temp
Подписаться на:
Сообщения (Atom)