Есть pdf документ. Я использую следующий код, для того, чтобы его открыть и изменить значение /Producer
public void CorrectPdf()
{
string path = "c:\temp\My.pdf");
byte[] bf = File.ReadAllBytes(path);
string s = Convert.ToBase64String(bf);
var decodeStr = Base64Decode(s);
//Здесь будет корректировка строки
//decodeStr.Replace(@"/Producer (HiQPdf 11.1)", "/Producer (MyMy)");
var encodeStr= Base64Encode(decodeStr);
var bf = Convert.FromBase64String(encodeStr);
System.IO.File.WriteAllBytes(path, bf);
}
public static string Base64Encode(string plainText)
{
var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
return System.Convert.ToBase64String(plainTextBytes);
}
public static string Base64Decode(string base64EncodedData)
{
var base64EncodedBytes = System.Convert.FromBase64String(base64EncodedData);
return System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
}
Не понимаю почему на выходе pdf документ с пустыми листами.
И хотелось бы получить полный ответ почему я немгу pdf считать в байты, затем перевести в строку
На это ответ очень прост: PDF - бинарный формат, а не текстовый. Любой код, который вызывает Encoding.GetString
на содержимом PDF-файла (в целом) можно смело выбрасывать. Конечно, преобразовывать в строку отдельные его поля, которые гарантированно являются текстом, можно.
Если вам нужно просто грубо заменить вхождение /Producer (Foo)
на /Producer (Bar)
, не учитывая структуру файла (т.е., если такая последовательность случайно встретится в содержимом файла, он будет поврежден), то можно сделать так:
using System;
using System.IO;
using System.Text;
class Program
{
public static bool SequenceEquals(byte[] array, int position, byte[] match)
{
if (match.Length > (array.Length - position)) return false;
for (int i = 0; i < match.Length; i++)
{
if (array[position + i] != match[i]) return false;
}
return true;
}
public static int FindSequence(byte[] arr, byte[] match, int startindex=0)
{
for (int i = startindex; i < arr.Length; i++)
{
if (SequenceEquals(arr, i, match)) return i;
}
return -1;
}
public static void Main()
{
string path1 = @"C:\Test\file1.pdf";
string path2 = @"C:\Test\file2.pdf";
//считаем данные
byte[] data = File.ReadAllBytes(path1);
//подготовим последовательности для поиска
byte[] match_start = Encoding.ASCII.GetBytes("/Producer");
byte[] match_end = Encoding.ASCII.GetBytes(")");
//найдем последовательность в массиве
int index_start = FindSequence(data, match_start);
int index_end = FindSequence(data, match_end, index_start + 1) + 1;
byte[] bytes_old = new byte[index_end - index_start];
Array.Copy(data, index_start, bytes_old, 0, bytes_old.Length);
string s_old = Encoding.ASCII.GetString(bytes_old);
//подготовим новые данные
string s_new = "/Producer (MyMy)";
byte[] bytes_new = Encoding.ASCII.GetBytes(s_new);
byte[] newdata = new byte[data.Length - bytes_old.Length + bytes_new.Length];
//запишем результат
Array.Copy(data, newdata, index_start);
Array.Copy(bytes_new, 0, newdata, index_start, bytes_new.Length);
Array.Copy(data, index_end, newdata, index_start+ bytes_new.Length, data.Length - index_end);
File.WriteAllBytes(path2, newdata);
Console.ReadKey();
}
}
Корректная замена должна учитывать структуру файла в соответствии с документацией Adobe.
Пожалуйста, не плюсуйте это сообщение, т. к. оно не является точным ответом на вопрос. Минусовать можно.
Рассмотрим ваш код по шагам.
Считали файл как массив байтов:
byte[] bf = File.ReadAllBytes(path);
Конвертировали массив байтов в base64:
string s = Convert.ToBase64String(bf);
Внутри метода Base64Decode
тут же конвертировали эту base64-строку обратно в байты:
var base64EncodedBytes = System.Convert.FromBase64String(base64EncodedData);
То есть содержимое массивов base64EncodedBytes
и bf
одинаково. Можно смело выкидывать эти действия.
Далее массив байтов преобразуется в строку:
return System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
Я не спец в PDF, однако быстрый поиск показывает, что внутри PDF могут быть разные кодировки. И не факт, что у вашего файла UTF-8. Поэтому вы могли получить кракозябры вместо текста.
После замены вы перегоняете строку в байты кодировки UTF-8.
Далее вы опять совершаете ненужные действия: массив байтов конвертируется в base64 и тут же обратно из base64 в массив байтов.
Как я понимаю, эти ненужные конвертации ничего не должны портить. Но они просто лишние и создают нагрузку на процессор и память.
Вообще, незачем читать сперва байты, а потом перекодировать их в текст в нужной кодировке. Можно это сделать сразу, вызовом одного метода:
var text = File.ReadAllText(path, Encoding.UTF8);
Тут делаем замену: text = text.Replace
.
Записываем аналогично:
File.WriteAllText(path, text, Encoding.UTF8);
Естественно, кодировки должны совпадать при чтении и записи.
Можно попробовать брутфорс: перебрать все кодировки.
foreach (var encoding in Encoding.GetEncodings())
Их довольно много. У меня показывает 140 штук.
Никто больше не отвечает, так что буду отдуваться.
Почему простая строковая замена не работает? Повторю, что я не спец в PDF. Но там вполне может быть структура данных с полями определённых размеров. И когда вы делаете замену:
decodeStr.Replace(@"/Producer (HiQPdf 11.1)", "/Producer (MyMy)");
то очевидно, что длины строк не совпадают. Из-за этого весь текст сдвигается. Но это же не просто текст - это структура данных со множеством полей, где хранится разметка страниц, шрифты, изображения и многое другое. В результате сдвига эти данные сломались. В итоге вы получаете пустые листы.
Самый лучший способ решения проблемы - взять библиотеку для работы с PDF, о чём уже писали в комментариях.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Есть определенные переменные, которые везде одинаковые, и которые можно вынести в отдельный файлКак мне в файле config
Коллеги, добрый деньЯ недавно занимаюсь разработкой на php и столкнулся с подобной проблемой
есть цикл, в нем выводяться записи с базы данных, в нем есть следующее условие "{% if loopindex != 1 and loop