Jak używać JavaScript z HTML do PDF przy użyciu C#

Jak używać JavaScript z HTML do PDF w C

This article was translated from English: Does it need improvement?
Translated
View the article in English

IronPDF umożliwia wykonywanie kodu JavaScript podczas konwersji HTML do PDF przy użyciu silnika renderującego Chromium. Konwertuj dynamiczne treści internetowe, w tym JavaScript i jQuery, na dokumenty PDF w aplikacjach .NET C# z obsługą elementów interaktywnych i dynamicznego renderowania.

JavaScript to wysokopoziomowy, wszechstronny język programowania używany w tworzeniu stron internetowych. Umożliwia korzystanie z interaktywnych i dynamicznych funkcji na stronach internetowych. jQuery to biblioteka JavaScript, która upraszcza typowe zadania, takie jak manipulacja DOM, obsługa zdarzeń i żądania AJAX.

IronPDF obsługuje JavaScript poprzez silnik renderujący Chromium. W tym artykułe pokazano, jak używać JavaScript i jQuery podczas konwersji HTML do PDF w projektach .NET C#. IronPDF udostępnia bezpłatną wersję próbną IronPDF do testów. Aby dowiedzieć się, jak debugować kod HTML przed konwersją, zapoznaj się z naszym przewodnikiem dotyczącym debugowania kodu HTML w przeglądarce Chrome.

Szybki start: Konwersja HTML z JavaScriptem do formatu PDF w .NET

Konwertuj strony HTML zawierające JavaScript do formatu PDF przy użyciu IronPDF w projektach .NET. Dzięki obsłudze silnika renderującego Chromium wszystkie elementy JavaScript są przetwarzane dokładnie. Ten przykład pokazuje, jak przekształcić stronę internetową z dynamiczną treścią do formatu PDF. Pojedyncze wywołanie metody renderuje i zapisuje dokument PDF.

  1. Install IronPDF with NuGet Package Manager

    PM > Install-Package IronPdf
  2. Skopiuj i uruchom ten fragment kodu.

    new IronPdf.ChromePdfRenderer { RenderingOptions = { EnableJavaScript = true, WaitFor = IronPdf.Rendering.WaitFor.JavaScript() } }
        .RenderHtmlAsPdf("<h1>Start</h1><script>document.write('<h1>Generated by JS</h1>');window.ironpdf.notifyRender();</script>")
        .SaveAs("js-rendered.pdf");
  3. Wdrożenie do testowania w środowisku produkcyjnym

    Rozpocznij używanie IronPDF w swoim projekcie już dziś z darmową wersją próbną

    arrow pointer

Jak skonfigurować podstawowy przebieg pracy?

  1. Pobierz bibliotekę C#: Konwersja HTML do PDF
  2. Właściwość EnableJavaScript
  3. RenderFromHtmlToPdf: Upewnij się, że kod JavaScript jest obsługiwany
  4. Wykonaj niestandardowy JavaScript: w kodzie C# .NET
  5. Zbieraj wiadomości konsoli: Używając listenera wiadomości JavaScript

Jak renderować JavaScript podczas konwersji HTML do PDF?

Podczas konwersji do formatu PDF obsługiwany jest JavaScript w HTML. Ponieważ renderowanie odbywa się natychmiastowo, JavaScript może nie działać poprawnie. Skonfiguruj klasę RenderingOptions w opcjach renderowania, aby zezwolić na czas wykonania JavaScriptu. Następujący kod używa WaitFor z maksymalnym czasem oczekiwania 500 ms. Szczegóły dotyczące czasów oczekiwania i opóźnień renderowania można znaleźć w naszym przewodniku korzystanie z WaitFor do opóźniania renderowania PDF.

WaitFor
WaitFor

Dlaczego WaitFor ma znaczenie dla wykonywania kodu JavaScript?

Złożone frameworki JavaScript mogą wymagać dostosowania alokacji pamięci ze względu na ograniczoną pamięć wykonawczą JavaScript w środowisku .NET Framework. RenderingOptions zapewnia opcje zapewniające pełne wykonanie JavaScript przed generowaniem PDF. Oczekiwanie na wykonanie kodu JavaScript, stany bezczynności sieci, elementy HTML lub niestandardowe opóźnienia renderowania. Dowiedz się więcej o dostępnych opcjach renderowania, aby zoptymalizować generowanie plików PDF.

Kiedy powinienem użyć metody notifyRender?

Metoda notifyRender sygnalizuje, że wykonanie JavaScriptu jest ukończone, zapewniając właściwe czasu renderowania dla dynamicznej zawartości. Użyj go do operacji asynchronicznych lub animacji, które muszą zostać zakończone przed wygenerowaniem pliku PDF. Metoda współpracuje z ustawieniami notifySettings dla precyzyjnej kontroli renderowania.

CustomJavaScript
InjectJavaScript
CaptureConsoleMessages

Jakie są typowe problemy związane z renderowaniem w JavaScript?

Złożone frameworki mogą wymagać dodatkowego czasu oczekiwania lub przydzielenia pamięci. Typowe problemy to:

  • Dane asynchroniczne nie są ładowane przed renderowaniem
  • Animacje CSS uchwycone w trakcie przejścia
  • Błędy JavaScript uniemożliwiające renderowanie
  • Ograniczenia pamięci przy rozbudowanych frameworkach

W celu rozwiązywania problemów należy włączyć niestandardowe logowanie, aby rejestrować szczegóły procesu renderowania.

Jak mogę wykonać niestandardowy kod JavaScript przed renderowaniem pliku PDF?

Użyj właściwości CustomJavaScript w opcjach renderowania, aby wykonać niestandardowy JavaScript przed renderowaniem. Jest to pomocne podczas renderowania adresów URL, gdzie nie jest możliwe wstrzyknięcie kodu JavaScript. Przypisz kod JavaScript do właściwości BeforeRendering w opcjach renderowania. Połącz z asynchronicznym generowaniem plików PDF w celu przetwarzania wielu dokumentów.

:path=/static-assets/pdf/content-code-examples/how-to/javascript-to-pdf-execute-javascript.cs
using IronPdf;

ChromePdfRenderer renderer = new ChromePdfRenderer();

// JavaScript code
renderer.RenderingOptions.Javascript = @"
document.querySelectorAll('h1').forEach(function(el){
    el.style.color='red';
})";

// Render HTML to PDF
PdfDocument pdf = renderer.RenderHtmlAsPdf("<h1>Happy New Year!</h1>");

pdf.SaveAs("executed_js.pdf");
Imports IronPdf

Private renderer As New ChromePdfRenderer()

' JavaScript code
renderer.RenderingOptions.Javascript = "
document.querySelectorAll('h1').forEach(function(el){
    el.style.color='red';
})"

' Render HTML to PDF
Dim pdf As PdfDocument = renderer.RenderHtmlAsPdf("<h1>Happy New Year!</h1>")

pdf.SaveAs("executed_js.pdf")
$vbLabelText   $csharpLabel

Kiedy należy stosować niestandardowe wstrzykiwanie kodu JavaScript?

Niestandardowe wstrzykiwanie kodu JavaScript działa podczas renderowania adresów URL, gdzie modyfikacja źródłowego kodu HTML nie jest możliwa. Typowe zastosowania:

  • Modyfikowanie stron stron trzecich przed konwersją
  • Dodawanie dynamicznych znaków wodnych lub nagłówków
  • Warunkowe ukrywanie lub wyświetlanie elementów
  • Dostosowanie stylów do układów drukarskich PRINT
  • Wyodrębnianie i reorganizacja treści

Jakie rodzaje manipulacji DOM mogę wykonywać?

Modyfikuj style, dodawaj elementy, zmieniaj treść lub wykonuj standardowe operacje DOM przed renderowaniem. Przykłady:

  • Zmiana właściwości CSS dotyczących formatowania wydruku PRINT
  • Usuń elementy nawigacyjne lub reklamy
  • Dodaj numery stron lub niestandardowe nagłówki
  • Zmiana struktury układu treści
  • Dodaj dodatkowe dane lub metadane

Jak przechwycić komunikaty konsoli JavaScript podczas generowania pliku PDF?

IronPDF przechwytuje komunikaty konsoli JavaScript, w tym logi błędów i komunikaty niestandardowe. Użyj właściwości ConsoleListener do przechwytywania wiadomości. Ten przykład pokazuje rejestrowanie niestandardowego tekstu i błędów.

:path=/static-assets/pdf/content-code-examples/how-to/javascript-to-pdf-message-listener.cs
using IronPdf;
using System;

ChromePdfRenderer renderer = new ChromePdfRenderer();

// Method callback to be invoked whenever a browser console message becomes available:
renderer.RenderingOptions.JavascriptMessageListener = message => Console.WriteLine($"JS: {message}");
// Log 'foo' to the console
renderer.RenderingOptions.Javascript = "console.log('foo');";

// Render HTML to PDF
PdfDocument pdf = renderer.RenderHtmlAsPdf("<h1> Hello World </h1>");

//--------------------------------------------------//
// Error will be logged
// message => Uncaught TypeError: Cannot read properties of null (reading 'style')
renderer.RenderingOptions.Javascript = "document.querySelector('non-existent').style.color='foo';";

// Render HTML to PDF
PdfDocument pdf2 = renderer.RenderHtmlAsPdf("<h1> Hello World </h1>");
Imports IronPdf
Imports System

Private renderer As New ChromePdfRenderer()

' Method callback to be invoked whenever a browser console message becomes available:
renderer.RenderingOptions.JavascriptMessageListener = Sub(message) Console.WriteLine($"JS: {message}")
' Log 'foo' to the console
renderer.RenderingOptions.Javascript = "console.log('foo');"

' Render HTML to PDF
Dim pdf As PdfDocument = renderer.RenderHtmlAsPdf("<h1> Hello World </h1>")

'--------------------------------------------------//
' Error will be logged
' message => Uncaught TypeError: Cannot read properties of null (reading 'style')
renderer.RenderingOptions.Javascript = "document.querySelector('non-existent').style.color='foo';"

' Render HTML to PDF
Dim pdf2 As PdfDocument = renderer.RenderHtmlAsPdf("<h1> Hello World </h1>")
$vbLabelText   $csharpLabel

Konsola debugowania pokazuje TypeError: Nie można odczytać właściwości null (odczytywanie 'stylu') z wyjściowym konsoli

Dlaczego warto monitorować komunikaty konsoli JavaScript?

Monitorowanie konsoli pomaga w debugowaniu błędów JavaScript i śledzeniu przebiegu wykonywania podczas generowania plików PDF. Niezbędne dla:

  • Identyfikacja błędów JavaScript uniemożliwiających renderowanie
  • Śledzenie postępu złożonych operacji JavaScript
  • Debugowanie problemów z synchronizacją kodu asynchronicznego
  • Sprawdzanie poprawności wykonywania niestandardowego kodu JavaScript
  • Gromadzenie wskaźników wydajności JavaScript

Jakie rodzaje komunikatów można przechwycić?

Naszunięty przechwyca niestandardowe wiadomości console.log i błędy JavaScript, w tym:

  • Wyjścia konsoli: log(), info(), warn(), error()
  • Nieprzechwycone wyjątki i błędy wykonania
  • Błędy sieciowe spowodowane nieudanym dostępem do zasobów
  • Ostrzeżenia o wycofaniu silnika przeglądarki
  • Niestandardowe informacje dotyczące debugowania
Icon Quote related to Jakie rodzaje komunikatów można przechwycić?

Moją ulubioną biblioteką tego typu jest IronPDF. Umożliwia ona szybkie i efektywne manipulowanie plikami PDF. Posiada także wiele cennych funkcji, takich jak eksport do formatu PDF/A i cyfrowe podpisywanie dokumentów PDF.

Milan Jovanovic related to Jakie rodzaje komunikatów można przechwycić?

Milan Jovanovic

Microsoft MVP

Zobacz studium przypadku
Icon Quote related to Jakie rodzaje komunikatów można przechwycić?

IronOCR pozwala nam oszczędzić 40 000 USD rocznie na ręcznym przetwarzaniu, jednocześnie zwiększając produktywność i uwalniając zasoby do zadań o wysokim wpływie. Gorąco polecam.

Brent Matzelle related to Jakie rodzaje komunikatów można przechwycić?

Brent Matzelle

Dyrektor technologiczny, OPYN

Zobacz studium przypadku
Icon Quote related to Jakie rodzaje komunikatów można przechwycić?

IronSuite odgrywa kluczową rolę w naszej działalności. Są to narzędzia zwiększające wydajność w całej firmie, w tym tworzenie planów pięter i poprawa zarządzania zapasami.

David Jones related to Jakie rodzaje komunikatów można przechwycić?

David Jones

Główny inżynier oprogramowania, Agorus Build

Zobacz studium przypadku

Jak tworzyć wykresy za pomocą bibliotek JavaScript, takich jak D3.js?

D3.js dobrze współpracuje z IronPDF przy tworzeniu wykresów lub obrazów. D3.js (Data-Driven Documents) to biblioteka JavaScript służąca do dynamicznej, interaktywnej wizualizacji danych przy użyciu SVG w HTML5 i CSS3. Więcej przykładów bibliotek do tworzenia wykresów można znaleźć w naszym przewodniku dotyczącym renderowania wykresów w plikach PDF.

Aby utworzyć wykres D3.js i przekonwertować go do formatu PDF:

  • Utwórz obiekt renderer
  • Ustaw właściwości JavaScript i CSS
  • Użyj HtmlToPdf do odczytu HTML
  • Zapisz jako PDF
:path=/static-assets/pdf/content-code-examples/how-to/javascript-to-pdf-render-chart.cs
using IronPdf;

string html = @"
<!DOCTYPE html>
<html>
<head>
<meta charset=""utf-8"" />
<title>C3 Bar Chart</title>
</head>
<body>
<div id=""chart"" style=""width: 950px;""></div>
<script src=""https://d3js.org/d3.v4.js""></script>
<!-- Load c3.css -->
<link href=""https://cdnjs.cloudflare.com/ajax/libs/c3/0.5.4/c3.css"" rel=""stylesheet"">
<!-- Load d3.js and c3.js -->
<script src=""https://cdnjs.cloudflare.com/ajax/libs/c3/0.5.4/c3.js""></script>

<script>
Function.prototype.bind = Function.prototype.bind || function (thisp) {
    var fn = this;
    return function () {
        return fn.apply(thisp, arguments);
    };
};
var chart = c3.generate({
    bindto: '#chart',
    data: {
        columns: [['data1', 30, 200, 100, 400, 150, 250],
                  ['data2', 50, 20, 10, 40, 15, 25]]
    }
});
</script>
</body>
</html>
";

// Instantiate Renderer
var renderer = new ChromePdfRenderer();

// Enable JavaScript
renderer.RenderingOptions.EnableJavaScript = true;
// Set waitFor for JavaScript
renderer.RenderingOptions.WaitFor.JavaScript(500);

// Render HTML contains JavaScript
var pdfJavaScript = renderer.RenderHtmlAsPdf(html);

// Export PDF
pdfJavaScript.SaveAs("renderChart.pdf");
Imports IronPdf

Private html As String = "
<!DOCTYPE html>
<html>
<head>
<meta charset=""utf-8"" />
<title>C3 Bar Chart</title>
</head>
<body>
<div id=""chart"" style=""width: 950px;""></div>
<script src=""https://d3js.org/d3.v4.js""></script>
<!-- Load c3.css -->
<link href=""https://cdnjs.cloudflare.com/ajax/libs/c3/0.5.4/c3.css"" rel=""stylesheet"">
<!-- Load d3.js and c3.js -->
<script src=""https://cdnjs.cloudflare.com/ajax/libs/c3/0.5.4/c3.js""></script>

<script>
Function.prototype.bind = Function.prototype.bind || function (thisp) {
    var fn = this;
    return function () {
        return fn.apply(thisp, arguments);
    };
};
var chart = c3.generate({
    bindto: '#chart',
    data: {
        columns: [['data1', 30, 200, 100, 400, 150, 250],
                  ['data2', 50, 20, 10, 40, 15, 25]]
    }
});
</script>
</body>
</html>
"

' Instantiate Renderer
Private renderer = New ChromePdfRenderer()

' Enable JavaScript
renderer.RenderingOptions.EnableJavaScript = True
' Set waitFor for JavaScript
renderer.RenderingOptions.WaitFor.JavaScript(500)

' Render HTML contains JavaScript
Dim pdfJavaScript = renderer.RenderHtmlAsPdf(html)

' Export PDF
pdfJavaScript.SaveAs("renderChart.pdf")
$vbLabelText   $csharpLabel

EnableJavaScript
WaitFor
WaitFor.JavaScript
window.ironpdf.notifyRender()
WaitFor.JavaScript
JavaScript
JavaScript
JavaScriptMessageListener
RenderHTMLFileAsPdf
WaitFor.NetworkIdle()
window.ironpdf.notifyRender()

Które biblioteki wykresów najlepiej współpracują z IronPDF?

Biblioteki do tworzenia wykresów w JavaScript kompatybilne z IronPDF:

  • Chart.js: Lekka biblioteka do tworzenia podstawowych wykresów
  • Highcharts: Professional wykresy z możliwością dostosowania
  • D3.js: Maksymalna elastyczność wizualizacji
  • C3.js: wykresy wielokrotnego użytku oparte na D3
  • ApexCharts: Nowoczesne wykresy o wysokiej wydajności

Powodzenie wymaga zakończenia renderowania wykresów przed wygenerowaniem pliku PDF przy użyciu odpowiednich strategii oczekiwania.

Kiedy należy dostosować czasy oczekiwania na renderowanie wykresów?

Złożone wykresy z animacjami lub dużymi zbiorami danych wymagają dłuższego czasu oczekiwania. Należy wziąć pod uwagę:

  • Objętość danych wpływa na czas przetwarzania
  • Animacja musi się zakończyć
  • Żądania sieciowe dla asynchronicznych danych
  • Złożoność wykresu zwiększa obciążenie przetwarzania

Jak mogę rozwiązać problemy z renderowaniem wykresów?

Zobacz 'Jak używać klasy WaitFor do opóźniania renderowania PDF w C#' dla więcej opcji WaitFor. Kroki rozwiązywania problemów:

  1. Zwiększ czas oczekiwania JavaScript
  2. Użyj HtmlToPdfAsync do asynchronicznego ładowania
  3. Wyłącz animacje w przypadku wyjścia PDF
  4. Sprawdź konsolę pod kątem błędów JavaScript
  5. Najpierw przetestuj kod HTML w przeglądarce

Jak przekonwertować aplikacje AngularJS do formatu PDF?

AngularJS to oparty na JavaScript otwarty framework front-endowy. Ułatwia tworzenie aplikacji jednostronicowych przy użyciu architektur MVC i MVVM po stronie klienta. Aby uzyskać więcej informacji, zapoznaj się z naszym przykładem kodu Angular do PDF.

Aby zapewnić kompatybilność, należy używać renderowania po stronie serwera (SSR) z Angular Universal. Aplikacje jednostronicowe (SPA) wymagają specjalnego traktowania ze względu na dynamiczne generowanie treści po początkowym załadowaniu.

Dlaczego renderowanie po stronie serwera jest ważne dla plików PDF w Angularze?

Angular po stronie klienta może nie wyświetlać się poprawnie bez SSR ze względu na zależność od JavaScript w przeglądarce. Wyzwania:

  • Minimalny początkowy HTML z dynamiczną zawartością
  • Routing po stronie klienta nie w statycznym HTML
  • Wiązanie danych po załadowaniu strony
  • Wywołania API niekompletne przed wygenerowaniem pliku PDF

Jakie są ograniczenia Angulara po stronie klienta?

Treści dynamiczne pojawiające się po początkowym załadowaniu mogą nie zostać uchwycone bez odpowiedniej konfiguracji czasu oczekiwania. Ograniczenia:

  • Asynchronicznie ładowane komponenty
  • Moduły ładowane leniwie i trasy
  • Animacje i przejścia
  • Dynamiczne formularze i interakcje
  • Aktualizacje danych w czasie rzeczywistym

Użyj dłuższych czasów oczekiwania lub zaimplementuj NotifyRender w swojej aplikacji Angular.

Jak działa renderowanie po stronie serwera w Angular Universal?

Jaka jest różnica między Angular a Angular Universal?

Angular działa po stronie klienta w przeglądarce, renderując strony w DOM na podstawie działań użytkownika. Angular Universal działa po stronie serwera, generując statyczne strony uruchamiane po stronie klienta. Poprawia to ładowanie i umożliwia przeglądanie układu przed uzyskaniem pełnej interaktywności.

Różnice w generowaniu plików PDF:

  • Angular: Wymaga wykonywania JavaScript
  • Angular Universal: Zapewnia wcześniej renderowany HTML
  • Wydajność: Uniwersal szybciej renderuje
  • Niezawodność: Universal zapewnia dostępność treści

Kiedy warto wybrać Angular Universal do generowania plików PDF?

Użyj Angular Universal, aby zapewnić dynamiczne renderowanie treści bez zależności od JavaScript po stronie klienta. Idealny dla:

  • Raporty z danymi z API
  • Dokumenty wymagające spójnego formatowania
  • Wysokiej objętości generowanie PDF
  • Złożone aplikacje Angular
  • Obawiasz się czasu oczekiwania wykonywania JavaScript

Angular Universal zapewnia renderowanie po stronie serwera przed konwersją do formatu IronPDF, co eliminuje problemy z synchronizacją i zwiększa niezawodność.

Często Zadawane Pytania

Jak wlaczyc JavaScript przy konwersji HTML na PDF w C#?

Aby wlaczyc JavaScript w IronPDF, ustaw w opcjach renderowania EnableJavaScript na true: new ChromePdfRenderer { RenderingOptions = { EnableJavaScript = true } }. To pozwala silnikowi Chromium w IronPDF wykonac JavaScript podczas procesu konwersji.

Jakie biblioteki JavaScript sa wspierane dla konwersji PDF?

IronPDF obsługuje wszystkie biblioteki JavaScript w tym jQuery, React, Vue.js i Angular za pomoca silnika renderujacego Chromium. Biblioteka moze przetwarzac manipulacje DOM, zapytania AJAX i generowanie dynamicznej zawartosci tak jak nowoczesna przegladarka.

Jak zarzadzac czasem wykonania JavaScript w generowaniu PDF?

Uzyj klasy WaitFor w opcjach renderowania IronPDF do kontroli czasu wykonania JavaScript. Mozesz uzyc WaitFor.JavaScript() z maksymalnym czasem oczekiwania (np. 500ms) aby upewnic sie, ze JavaScript sie zakonczyl przed generowaniem PDF: WaitFor = IronPdf.Rendering.WaitFor.JavaScript(500).

Czy moge wykonac wlasny kod JavaScript podczas konwersji HTML na PDF?

Tak, IronPDF pozwala na wykonanie wlasnego kodu JavaScript w twojej aplikacji .NET C# podczas procesu konwersji. Mozesz wstrzyknac JavaScript bezposrednio do ciagu HTML lub uzywac opcje renderowania do uruchamiania wlasnych skryptow.

Jak przechwycic komunikaty konsoli JavaScript podczas renderowania PDF?

IronPDF oferuje funkcje sluchania komunikatow JavaScript, która umożliwia przechwytywanie komunikatow console.log i innych danych wyjsciowych JavaScript podczas procesu renderowania PDF. Jest to przydatne do szukania bledow w wykonaniu JavaScript.

Jakiego silnika renderujacego uzywa biblioteka do wsparcia JavaScript?

IronPDF uzywa silnika renderujacego Chromium, tego samego silnika, ktory napedza Google Chrome. To zapewnia pelna zgodnosc JavaScript i dokladne renderowanie nowoczesnych technologii internetowych w twoich dokumentach PDF.

Czy jest dostepna bezplatna proba dla testowania konwersji JavaScript na PDF?

Tak, IronPDF oferuje bezplatna probe, która obejmuje pelne wsparcie dla JavaScript. Mozesz przetestowac wszystkie funkcje, w tym wykonanie JavaScript, renderowanie jQuery i generowanie dynamicznej zawartosci przed zakupem licencji.

Curtis Chau
Autor tekstów technicznych

Curtis Chau posiada tytuł licencjata z informatyki (Uniwersytet Carleton) i specjalizuje się w front-endowym rozwoju, z ekspertką w Node.js, TypeScript, JavaScript i React. Pasjonuje się tworzeniem intuicyjnych i estetycznie przyjemnych interfejsów użytkownika, Curtis cieszy się pracą z nowoczesnymi frameworkami i tworzeniem dobrze zorganizowanych, atrakcyjnych wizualnie podrę...

Czytaj więcej
Gotowy, aby rozpocząć?
Nuget Pliki do pobrania 19,936,792 | Wersja: 2026.7 właśnie wydany
Still Scrolling Icon

Wciąż przewijasz?

Czy chcesz szybko dowodu? PM > Install-Package IronPdf
Uruchom przykład i zobacz, jak Twój kod HTML zamienia się w plik PDF.