Formats7 min czytania

Jak działa edycja tekstu w PDF: strumienie treści, kodowania czcionek i dlaczego można edytować tylko jeden wiersz naraz

Strona PDF nie ma akapitów ani pól tekstowych, tylko instrukcje narysowania glifów daną czcionką w danym miejscu. Edycja wiersza usuwa stare instrukcje i zapisuje nowe w tym samym miejscu, a to przesądza, co można edytować, a czego nie.

PDF123 · Updated 2026-10-14
Jak działa edycja tekstu w PDF: strumienie treści, kodowania czcionek i dlaczego można edytować tylko jeden wiersz naraz

Strona PDF nie ma akapitów ani pól tekstowych. Ma listę instrukcji: w tym miejscu, tą czcionką i w tym rozmiarze narysuj te glify. Zmiana tekstu oznacza usunięcie instrukcji, które rysują dany wiersz, i zapisanie nowych w tym samym miejscu, tą samą czcionką, w tym samym rozmiarze i kolorze. Dlatego Edytuj PDF edytuje jeden wiersz naraz i nie zawija tekstu: wynika to ze sposobu, w jaki tekst jest zapisany.

Jak wygląda jeden wiersz tekstu w pliku

Treść strony znajduje się w strumieniu treści, małym programie złożonym z operatorów. Dla tekstu większość pracy wykonują cztery operatory: BT i ET ujmują blok tekstu, Tf wybiera czcionkę i rozmiar, Td przesuwa do następnej pozycji, a Tj rysuje ciąg znaków. Ze standardową czcionką najprostszy przypadek wygląda tak:

BT /F1 18 Tf 20 150 Td (Hello World) Tj ET

Oznacza to: wybierz czcionkę F1 w rozmiarze 18 punktów, przesuń się do x 20, y 150 i narysuj Hello World. PDF wydrukowany z Chrome zwykle wygląda inaczej: w nawiasach nie ma już znaków, tylko numery glifów z czcionki, a Tm ustawia pozycję raz. Poniżej wiersz Hello World from Georgia ze strony wyeksportowanej z Chrome, gdzie każde cztery cyfry szesnastkowe to jeden numer glifu:

BT /F4 24 Tf 1 0 0 -1 30 52 Tm <002b0048004f004f00520003003a00520055004f0047000300490055005200500003002a004800520055004a004c0044> Tj ET

002b to H, 0048 to e, 004f to l, 0003 to spacja, 003a to W i tak dalej. Te liczby mają sens tylko w obrębie tej jednej czcionki; to nie jest Unicode. Gdy kopiujesz tekst, czytnik PDF zamienia numery z powrotem na znaki za pomocą tabeli przeglądowej zapisanej gdzie indziej w pliku.

Wynikają z tego dwie rzeczy. Po pierwsze, nic w strumieniu treści nie mówi „to jest akapit”: koniec wiersza to po prostu kolejny Td lub Tm, który przesuwa pozycję do następnego wiersza, a ile wierszy ma akapit, trzeba wnioskować z pozycji. Po drugie, aby wpisać do wiersza nowy znak, potrzebny jest numer tego znaku w tej czcionce, a czcionka często zawiera tylko glify użyte w chwili zapisu pliku. To skutek zawężania czcionek.

Strumienie można rozwinąć za pomocą qpdf:

qpdf --qdf --object-streams=disable in.pdf out.pdf

Otwórz out.pdf w edytorze tekstu i wyszukaj Tj, aby zobaczyć każdy ciąg rysowany na stronie. O tym, co jeszcze zawiera PDF, przeczytasz w artykule Co jest w środku PDF: obiekty, strumienie i tabela odsyłaczy.

Jak edytor odtwarza „wiersz” z glifów

Edytor musi najpierw zgrupować luźne glify w wiersz, który użytkownik może kliknąć. Fragment to grupa sąsiednich glifów o tej samej czcionce, rozmiarze i kolorze, których odstęp od poprzedniego glifu nie przekracza jednego rozmiaru czcionki; koniec wiersza, nowa czcionka lub nowy kolor kończą fragment. Tekst biegnący od prawej do lewej albo pionowo nie jest grupowany i nie można go otworzyć do edycji.

Dwie konsekwencje widać bezpośrednio. Wiersz mieszający dwie czcionki, na przykład chiński wiersz z angielskim słowem, dzieli się na dwa sąsiednie fragmenty, które klika się osobno. Po edycji dzieje się to samo: jeśli nowy tekst używa innej czcionki, wiersz staje się dwoma fragmentami, a edycja jednego z nich zostawia drugi bez zmian.

Edycja wiersza: usunięcie starego tekstu, potem zapis nowego

Usuwanie używa odmiany zaciemniania wyłącznie dla tekstu: glify w obszarze wiersza są usuwane ze strumienia treści, obrazy i linie zostają, na starym tekście nie rysuje się kolorowego prostokąta, więc kopiowanie i wyszukiwanie już go nie znajdują. Zmienia to tylko treść strony; jeśli ten sam tekst występuje także w adnotacji albo we właściwościach dokumentu, nie ma to na nie wpływu.

Zapis dopisuje nową instrukcję tekstową na końcu strumienia treści strony, zaczynając od położenia linii bazowej oryginalnego wiersza i używając jego rozmiaru i koloru. Po zmianie powyższego wiersza na Hello World 2 na końcu strony dopisywane jest:

q 1 0 0 1 22.5 148.92 cm 0 0 0 rg
/Span <</ActualText <feff00480065006c006c006f00200057006f0072006c006400200032>>> BDC
BT /F4 18 Tf 0 0 Td <002b0048004f004f00520003003a00520055004f00470003> Tj ET
BT /F9 18 Tf 102.18 0 Td (2) Tj ET
EMC
Q

Pierwszy BT używa oryginalnej czcionki F4 i oryginalnych numerów glifów, więc Hello World jest użyte ponownie dokładnie tak, jak było. Cyfry „2” nie ma w oryginalnym podzbiorze czcionki, więc drugi BT uruchamia nową standardową czcionkę Helvetica (F9), aby ją narysować. q i Q ograniczają przekształcenie współrzędnych i kolor tego bloku do niego samego; edytor obejmuje też oryginalną treść parą q/Q, aby niezrównoważony stan pozostawiony na końcu oryginalnej strony nie wpłynął na nowy tekst. Tak wyglądał jeden fragment; liczby różnią się w zależności od pliku.

Dopisywanie na końcu ma trzy konsekwencje:

  • Nowy tekst jest rysowany jako ostatni, na wierzchu wszystkiego innego na stronie. Tekst, który leżał pod obrazem lub kolorowym blokiem, po edycji pojawia się nad nim.
  • Narzędzie wydobywające tekst w kolejności strumienia treści (takie jak pdftotext -raw) czyta edytowany wiersz jako ostatni na tej stronie, a wydobywanie według pozycji (pdftotext -layout) nie pokazuje żadnej zmiany. Strona wygląda tak samo, ale kolejność czytania się zmieniła.
  • Edytor dołącza do nowego tekstu ActualText, który mówi czytnikowi, jakim rzeczywistym znakom odpowiadają glify. Jeden glif może odpowiadać kilku znakom, a szukanie wyłącznie po numerze glifu zwraca czasem znak zgodnościowy (na przykład dla 文 znajdowany jest klucz Kangxi ⽂); ActualText zapewnia, że skopiowane jest to, co wpisałeś.

Jaka czcionka rysuje nowy tekst

Ponowne użycie oryginalnej czcionki jest najbezpieczniejsze, bo kształt glifów, grubość i szerokość pasują do sąsiedniego tekstu. To, czy można ją użyć, zależy od tego, czy edytor potrafi ustalić, jaki kod ma dany znak w tej czcionce:

  • Czcionka złożona taka jak powyższa (Type0, dwubajtowe numery glifów, kodowanie Identity-H): znak jest wyszukiwany w czcionce, aby uzyskać numer glifu, i jeśli zostanie znaleziony, jest używany. Jeśli nie zostanie znaleziony, znaku nie ma w podzbiorze.
  • Jednobajtowa czcionka prosta (TrueType, Type1) z kodowaniem WinAnsi lub MacRoman: odwzorowanie znaku na bajt jest stałe, a szerokości pochodzą z tabeli szerokości w pliku.
  • Czcionka z własnym kodowaniem (Differences) albo oparta na wbudowanym kodowaniu czcionki: nie ma wiarygodnego odwzorowania, więc edytor nie zgaduje i przechodzi na czcionkę zastępczą, inaczej tekst wyszedłby zniekształcony.

Gdy znaku nie ma w oryginalnej czcionce, używana jest czcionka zastępcza. Zwykłe litery łacińskie są rysowane najbliższą z czcionek Helvetica, Times i Courier, standardowych czcionek, które ma każdy czytnik, więc nic nie trzeba osadzać. Wszystko inne, na przykład chińskie znaki, kana, hangul, pismo tajskie, litery łacińskie z diakrytykami, cyrylica i greka, używa otwartej czcionki Noto: serwer bierze znaki z żądania i wycina z pełnej czcionki tylko te glify za pomocą biblioteki HarfBuzz na otwartej licencji do tworzenia podzbiorów, zwykle kilka KB, a przeglądarka osadza je w twoim pliku. Regionalna odmiana chińskiego znaku zależy od języka interfejsu: uproszczona, tradycyjna, japońska lub koreańska.

Glify są osadzane zamiast zapisywania samej nazwy czcionki, ponieważ czcionkę wskazaną wyłącznie nazwą każdy czytnik zastępuje własną czcionką zastępczą, a grubość może się między czytnikami różnić; po osadzeniu każdy czytnik pokazuje te same kształty.

Dlaczego tylko jeden wiersz naraz

Edytor nie ma silnika składu. Położenie każdego glifu jest zapisane w pliku na stałe; nowy tekst jest po prostu układany w prawo od punktu początkowego według szerokości czcionki, bez logiki „zawiń przy krawędzi”, a nic po nim nie jest przesuwane. Jeśli wydłużysz wiersz, dodatkowe znaki biegną dalej w prawo, a to, co wyjdzie poza krawędź strony, nie jest widoczne. Przepisanie akapitu albo dodanie wierszy do tabeli wymaga nowego składu, czyli powrotu do pliku źródłowego, z którego PDF powstał.

Szerokości pochodzą też wyłącznie z samej czcionki (o tyle przesuwa się pozycja po każdym glifie), bez kerningu i bez podmiany glifów. Tekst, który nie wymaga kształtowania, czyli doboru i ustawiania glifów zależnie od kontekstu (łacina, cyrylica, greka i chińskie znaki), jest układany poprawnie. Tajskie znaki tonów wymagają pozycjonowania glifów, aby stanąć we właściwym miejscu, czego edytor nie robi, więc mogą być przesunięte. Arabski wymaga kontekstowych form glifów i układu od prawej do lewej, hebrajski wymaga układu od prawej do lewej, a pisma indyjskie wymagają łączenia spółgłosek i znaków samogłoskowych w glify; wszystko to wymaga pełnego kształtowania tekstu, którego edytor obecnie nie wykonuje, więc wpisywanie ich jest odrzucane zamiast dawać błędne znaki.

Dwa kolejne ograniczenia wynikają z samego pliku. Treść zeskanowanej strony to jeden obraz bez operatorów tekstowych, więc nie ma czego usuwać ani zmieniać. Po edycji pliku z podpisem cyfrowym oryginalna treść, którą podpis chronił, uległa zmianie i podpis przestaje być ważny.

Sprawdź sam

Opisane zmiany możesz zobaczyć w pobranym pliku za pomocą trzech poleceń:

pdftotext -raw edited.pdf -      # wydobycie w kolejności strumienia treści: starego tekstu nie ma, edytowany wiersz jest ostatni
pdffonts edited.pdf              # lista czcionek: oryginalne czcionki użyte ponownie i nowo osadzony podzbiór czcionki
qpdf --qdf --object-streams=disable edited.pdf edited.qdf   # rozwija strumień treści; dopisany blok BT ... ET jest na końcu

Czytaj dalej

Open tool
Process in the browser — no watermark, files removed after the job.
Open tool