docx. Добавить картинку в колонтитул
От: BlackEric http://black-eric.lj.ru
Дата: 03.02.24 10:58
Оценка: 5 (1)
Добрый день.

Нужно в уже существующий нижний колонтитул docx файла добавить изображение. При этом в колонтитуле уже может быть текст.
Хотелось бы что бы это работало на сервере без использования установленного ворда.

Какие библиотеки использовать и нет ли примера кода?
https://github.com/BlackEric001
Re: docx. Добавить картинку в колонтитул
От: Ромашка Украина  
Дата: 03.02.24 15:51
Оценка: 41 (1)
Здравствуйте, BlackEric, Вы писали:
BE>Какие библиотеки использовать и нет ли примера кода?

Решение "в лоб". Берешь 1.docx, вставляешь туда изображение, называешь 2.docx. Переименовываешь два файла в *.zip, разархивируешь. Смотришь что изменилось. Создаешь простейшее приложение, которое разархивирует входящий файл, добавляет в нужную директорию картинку, добавляет в нужное место нужного xml нужный тег, архивирует это назад и отдает пользователю.

Решение "на вырост" — ищешь библиотеку, которая работает с ODF и которая будет делать вышеописанное без твоего участия. В том числе создает колонтитул если его нет, например.

Ну или можешь покопаться в стандарте ODF (Open Document Format), результат будет приблизительно тем же, но ты будешь понимать как оно работает.


UPD упс, сорри, мелкомягкие называют свой стандарт Open XML, ODF это OpenOffice.


Всё, что нас не убивает, ещё горько об этом пожалеет.
Отредактировано 03.02.2024 15:55 Ромашка . Предыдущая версия .
Re: docx. Добавить картинку в колонтитул
От: Михаил Романов Удмуртия https://mihailromanov.wordpress.com/
Дата: 03.02.24 17:52
Оценка: 104 (3)
Здравствуйте, BlackEric, Вы писали:

BE>Какие библиотеки использовать и нет ли примера кода?

О! Этот вопрос всплывает регулярно раз в несколько лет, и хоть я не работаю с этим уже лет 10 (а то и больше), но каждый раз приятно вспомнить и покопаться — а что актуально на сегодня.

В общем, если у вас предстоит много работы по манипуляции документами Word, то я бы порекомендовал всё же посмотреть на что-то типа Aspose.Words. Они считаются самыми крутыми по части поддержки форматов Office.
Другой вопрос, что ценник там тоже не милосердный, и приобрести их в России может быть сейчас не реальным...
Есть и другие коммерческие решение (например те же ComponentOne), но я не слышал, чтобы их кто-то рассматривал серьезно для работы с офисными форматами.

Если вы ориентируетесь на свободные/бесплатные решения, то тут всё просто
Первое место, конечно же, OpenXML SDK
Это:
— решение от Microsoft (причем не заброшенное, а поддерживаемое и даже развиваемое — не так давно вышли серьезное доработки всего NuGet пакета(ов))
— там поддерживается гарантированно всё, что есть в стандарте OpenXML
— по нему куча документации как от самого MS, так и сторонних

Но... это своего рода ассемблер для офисных форматов. Т.е. вы вынуждены манипулировать самыми низкоуровневыми конструкциями (вот, пример близкий к тому, что вы просили how to add footer with images in word document in .net
Т.е. чтобы им пользоваться нужно очень хорошо понимать структуру офисных форматов (вот еще примерчик — банальная вставка картинки)

Можно попытаться воспользоваться чем-то вроде Open XML SDK 2.5 Productivity Tool и взять за основу совет, который дал коллега Ромашка, в соседнем посте (т.е. сравнить файл до и после изменений).
Эту утилита реально умеет сравнивать файлы Office и (главное!) умеет генерировать код с использование OpenXML SDK, для генерации как всего файла, так и выбранных вами изменений.
Но это примерно как "взять две версии софтины — до и после внесения изменений. Дизассемблировать и на основе diff листингов дизассемблера попытаться родить свое решение".

Более перспективным выглядит взять надстройку над OpenXML SDK, которая бы имела более человечный API. Правда, для Word я знаю только OfficeIMO, а умеет ли она то, что вам нужно, я с ходу понять не смог.

Если же OfficeIMO не подойдет, можно взглянуть на DocX, но, судя по тому, что написано в readme проекта, нужный вам функционал есть только в платной версии (Xceed Words for .NET), а DocX оставлен очень и очень ущербным...
Re[2]: docx. Добавить картинку в колонтитул
От: BlackEric http://black-eric.lj.ru
Дата: 05.02.24 07:00
Оценка:
Здравствуйте, Михаил Романов, Вы писали:

А можно ли это реализовать через NPOI?
Как я понял — это тоже обертка над OpenXML.
https://github.com/BlackEric001
Re[3]: docx. Добавить картинку в колонтитул
От: Михаил Романов Удмуртия https://mihailromanov.wordpress.com/
Дата: 05.02.24 12:21
Оценка:
Здравствуйте, BlackEric, Вы писали:

BE>Здравствуйте, Михаил Романов, Вы писали:


BE>А можно ли это реализовать через NPOI?

Не могу сказать, может быть и можно.
Вообще, NPOI был в свое время интересен поддержкой бинарных офисных форматов (doc, xls, ...) и когда пошел переход на OpenXML (и появился OpenXML SDK) они стали не особо интересны и я их из виду потерял.
Судя по всему, они перестроились и добавили поддержку OpenXML. Хотя, возможно это уже совсем другая команда, потому что в сети какое-то приличное количество форков NPOI.

Честно говоря, я немного скептически смотрел ранее на NPOI, т.к. это был форм Java POI и интерфейс многих классов выглядел как-то своеобразно. Сейчас, как я понимаю, они никак не связаны, так что может всё и поменялось

BE>Как я понял — это тоже обертка над OpenXML.

На сколько могу судить — нет, у них свой собственный парсинг и сериализация. Я специально посмотрел по зависимостям NuGet пакета — ссылок на OpenXML SDK не нашел.
Re: docx. Добавить картинку в колонтитул
От: BlackEric http://black-eric.lj.ru
Дата: 13.02.24 14:00
Оценка: 1 (1)
Здравствуйте, BlackEric, Вы писали:

BE>Добрый день.


BE>Нужно в уже существующий нижний колонтитул docx файла добавить изображение. При этом в колонтитуле уже может быть текст.

BE>Хотелось бы что бы это работало на сервере без использования установленного ворда.

BE>Какие библиотеки использовать и нет ли примера кода?


Сделали в итоге на java apachr poi. В npoi методы вставки таблицы в колонтитул не реализованы.

package ru.blackeric.poitest;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlCursor;


/**
 *
 * @author Eric
 */
public class PoiTest {

    public static void main(String[] args) throws IOException, InvalidFormatException {
        System.out.println("Hello World!");

        String srcFileName = "t:\\FileName_3.docx";
        String dstFileName = "t:\\FileName_jq.docx";

        FileInputStream fis = new FileInputStream(srcFileName);
        try (XWPFDocument document = new XWPFDocument(fis)) {

            var footerList = document.getFooterList();
            
            for(XWPFFooter f : footerList) {
                // 1. Read existing text from footer
                String text = f.getText();
                System.out.println(text);
                
                // 2. Сбрасываем все что есть
                f.setHeaderFooter(org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHdrFtr.Factory.newInstance());
                
                 var paragraph = f.createParagraph();
                 XmlCursor cursor = paragraph.getCTP().newCursor();
                
                var insertedTable = f.insertNewTbl(cursor);
                
                var row = insertedTable.createRow();
                var cell0 = row.createCell();
                var p = cell0.addParagraph();
                var ir = p.createRun();
                FileInputStream imageInputStream = new FileInputStream("t:\\image.png");
                ir.addPicture(imageInputStream, XWPFDocument.PICTURE_TYPE_PNG, "addedimage", 100 * 9225, 100 * 9225);
                ir.addCarriageReturn();
                ir.setFontSize(8);
                ir.setText("Text for image");
                
                var cell1 = row.createCell();
                var p1 = cell1.addParagraph();
                var ir1 = p1.createRun();
                ir1.setFontSize(8);
                ir1.setText(text);
                
            }
            
            // save it to .docx file
            try (FileOutputStream out = new FileOutputStream(dstFileName)) {
                document.write(out);
            }

        }
        System.out.println("The End!");
    }
}
https://github.com/BlackEric001
Re[2]: docx. Добавить картинку в колонтитул
От: Михаил Романов Удмуртия https://mihailromanov.wordpress.com/
Дата: 13.02.24 15:05
Оценка:
Здравствуйте, BlackEric, Вы писали:

BE>Сделали в итоге на java apachr poi. В npoi методы вставки таблицы в колонтитул не реализованы.

А пробовали OfficeIMO?
Я у них увидел вот такой пример для картинок

Там есть пример вставки картинки в footer, правда в сравнении с вашим он сильно упрощен (просто напрямую в параграф без добавления таблицы.

Если пробовали, то почему решили отказаться? (я так понимаю у вас .Net и подтягивать Java для решения отдельной небольшой задачки я бы, честно говоря, не решился — как-то слишком сложно для поддержки выглядит).
Re: docx. Добавить картинку в колонтитул
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 13.02.24 15:46
Оценка:
Здравствуйте, BlackEric, Вы писали:

BE>Какие библиотеки использовать и нет ли примера кода?

Посмотри в сторону OpenXml
https://learn.microsoft.com/ru-ru/dotnet/api/documentformat.openxml.wordprocessing.footer?view=openxml-2.8.1
и солнце б утром не вставало, когда бы не было меня
Re[3]: docx. Добавить картинку в колонтитул
От: BlackEric http://black-eric.lj.ru
Дата: 14.02.24 08:23
Оценка:
Здравствуйте, Михаил Романов, Вы писали:

МР>Здравствуйте, BlackEric, Вы писали:


BE>>Сделали в итоге на java apachr poi. В npoi методы вставки таблицы в колонтитул не реализованы.

МР>А пробовали OfficeIMO?
МР>Я у них увидел вот такой пример для картинок

МР>Там есть пример вставки картинки в footer, правда в сравнении с вашим он сильно упрощен (просто напрямую в параграф без добавления таблицы.


МР>Если пробовали, то почему решили отказаться? (я так понимаю у вас .Net и подтягивать Java для решения отдельной небольшой задачки я бы, честно говоря, не решился — как-то слишком сложно для поддержки выглядит).


string filePath = @"C:\Support\GitHub\PSWriteOffice\Examples\Documents\BasicDocument.docx";

using (WordDocument document = WordDocument.Create(filePath)) {
    document.Title = "This is my title";
    document.Creator = "Przemysław Kłys";
    document.Keywords = "word, docx, test";

    var paragraph = document.AddParagraph("Basic paragraph");
    paragraph.ParagraphAlignment = JustificationValues.Center;
    paragraph.Color = SixLabors.ImageSharp.Color.Red;

    document.Save(true);
}


Вот этот пример из read.me уже не собирается, говорит, что не знает Title, Creator, Keywords и JustificationValues. Дальше продираться не стал. И у нас 5 dotnet, а там его нет в поддерживаемых.

Может на основе java исходников доработаем npoi, не знаю пока.
https://github.com/BlackEric001
Re[4]: docx. Добавить картинку в колонтитул
От: Михаил Романов Удмуртия https://mihailromanov.wordpress.com/
Дата: 14.02.24 08:50
Оценка:
Здравствуйте, BlackEric, Вы писали:

BE>Вот этот пример из read.me уже не собирается, говорит, что не знает Title, Creator, Keywords и JustificationValues. Дальше продираться не стал. И у нас 5 dotnet, а там его нет в поддерживаемых.

Ну отчасти, конечно, соглашусь — неработающий пример с главной страницы роняет продукт в глазах на добрый десяток пунктов.
Не в оправдание им, но всё же я просто глянул следующий пример и сразу стало понятно, что поправить (видимо, они убрали базовые свойства, типа того же Title в отдельный объект/свойство BuiltinDocumentProperties, а пример поправить никто не подумал)
string filePath = @"d:\temp\OfficeIMO\BasicDocument.docx";

using (var document = WordDocument.Create(filePath))
{
    document.BuiltinDocumentProperties.Title = "This is my title";
    document.BuiltinDocumentProperties.Creator = "Przemysław Kłys";
    document.BuiltinDocumentProperties.Keywords = "word, docx, test";

    var paragraph = document.AddParagraph("Basic paragraph");
    paragraph.ParagraphAlignment = JustificationValues.Center;
    paragraph.Color = SixLabors.ImageSharp.Color.Red;

    document.Save(true);
}


Ну и с поддержкой .Net 5.0 всё нормально — там просто подхватывается .Net Standard 2.1

Конечно смотрите и решайте сами. Мне лично кажется доработка NPOI будет весьма затратным удовольствием.
Но, возможно, у вас есть серьезные резоны в его использовании (та же потенциальная работа со старыми бинарными форматами).
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.