' . esc_html__( 'Back to library', 'affstackdev-image-manager' ) . '

' . esc_html( $convert ? __( 'Create an image from a PDF page', 'affstackdev-image-manager' ) : __( 'Replace an attachment with undo', 'affstackdev-image-manager' ) ) . '

' . esc_html( get_the_title( $id ) ) . '

'; if ( $convert ) { echo '

' . esc_html__( 'Render one page on this server, review it, then save a separate PNG image. The original PDF and its existing links stay available. Text, layout and artwork are flattened into the image; PDF links and selectable text are not carried into it.', 'affstackdev-image-manager' ) . '

' . esc_html__( 'Open the source PDF', 'affstackdev-image-manager' ) . '

'; } else { echo '

' . esc_html__( 'The attachment ID stays the same. The replacement gets a new file URL and WordPress image sizes. WordPress-rendered uses of the ID can follow it; direct URLs saved in pages, CSS or external sites keep showing the old files. Review those uses separately.', 'affstackdev-image-manager' ) . '

' . esc_html__( 'A verified local recovery ZIP is required before applying. Old files are retained, and Undo returns this attachment to its previous file and metadata.', 'affstackdev-image-manager' ) . '

'; } if ( $draft && 'saved' === $draft['state'] ) { $result = (int) $draft['result']; /* translators: %d: attachment ID of the new image, or of the attachment whose file was replaced. */ echo '

' . esc_html( $convert ? sprintf( __( 'Image saved as media #%d.', 'affstackdev-image-manager' ), $result ) : sprintf( __( 'Replacement applied to media #%d.', 'affstackdev-image-manager' ), $id ) ) . ' ' . esc_html__( 'Open attachment', 'affstackdev-image-manager' ) . '

'; } elseif ( $draft && 'prepared' === $draft['state'] ) { $url = Media_Draft::url( $id, $kind, $draft['id'] ); echo '
'; if ( ! $convert ) { echo '
' . esc_html__( 'Current source', 'affstackdev-image-manager' ) . '
' . esc_attr__( 'Current image', 'affstackdev-image-manager' ) . '
'; } echo '
' . esc_html__( 'Private preview', 'affstackdev-image-manager' ) . ' · ' . (int) $draft['image']['width'] . ' × ' . (int) $draft['image']['height'] . '
' . esc_attr__( 'Prepared image preview', 'affstackdev-image-manager' ) . '
'; if ( $convert ) { /* translators: %d: PDF page number. */ echo '

' . esc_html( sprintf( __( 'PDF page %d · white background · PNG. This creates a normal selectable image for WordPress or WooCommerce.', 'affstackdev-image-manager' ), (int) $draft['recipe']['page'] ) ) . '

'; } if ( time() - (int) $draft['created'] < DAY_IN_SECONDS ) { $begin( $convert ? 'pdf_save' : 'replace_apply' ); echo ''; } else { echo '

' . esc_html__( 'This preview has expired. Prepare a fresh preview to continue.', 'affstackdev-image-manager' ) . '

'; } $begin( 'media_draft_discard' ); echo ''; } if ( $revision ) { $state = $revision['state'] ?? ''; echo '
' . esc_html__( 'Replacement recovery', 'affstackdev-image-manager' ) . ''; if ( ! empty( $revision['backup'] ) ) { /* translators: %s: link to the recovery ZIP, reading "Inspect and download the pre-replacement recovery ZIP". */ echo '

' . sprintf( esc_html__( '%s. Local temporary storage can be purged by your host; download a copy to keep it.', 'affstackdev-image-manager' ), '' . esc_html__( 'Inspect and download the pre-replacement recovery ZIP', 'affstackdev-image-manager' ) . '' ) . '

'; } if ( in_array( $state, array( 'applied', 'applying', 'undoing' ), true ) ) { $recover = 'applying' === $state; $begin( $recover ? 'replace_recover' : 'replace_undo' ); echo ''; } else { echo '

' . esc_html( 'undone' === $state ? __( 'The latest replacement was undone.', 'affstackdev-image-manager' ) : __( 'The interrupted replacement was recovered.', 'affstackdev-image-manager' ) ) . '

'; } echo '
'; } if ( ! $draft || 'prepared' !== $draft['state'] ) { if ( $convert ) { if ( ! PDF::available() ) { echo '

' . esc_html__( 'This host needs PHP Imagick with permission to read PDF through Ghostscript. PDF browsing, organization and downloads remain available.', 'affstackdev-image-manager' ) . '

'; } else { $begin( 'pdf_prepare' ); echo '

' . esc_html__( 'One page per request, up to page 500 and a 64 MiB source. Host PDF restrictions and resource limits can prevent conversion. No media is sent to an external service.', 'affstackdev-image-manager' ) . '

'; } } elseif ( ! in_array( $revision['state'] ?? '', array( 'applying', 'undoing' ), true ) ) { $begin( 'replace_prepare' ); /* translators: %s: the attachment's file type, such as image/jpeg. */ echo '

' . esc_html__( 'The file must use the current image format. Maximum 64 MiB and 24 megapixels, subject to your host’s lower upload limit. No file is replaced just by opening this screen.', 'affstackdev-image-manager' ) . '

'; } } echo ''; } /** * 1.9.0 (D-500 gap 15): a smaller copy of a PDF, prepared, looked at and saved as a new media item (PDF_Copy). * * @param int $id The PDF attachment. * @param callable $begin Opens a form for an operation. * @param string $back The library's address. * @return void * @throws \RuntimeException With media_action_source when the attachment is not a PDF. */ private static function compress( int $id, callable $begin, string $back ): void { if ( 'application/pdf' !== (string) get_post_mime_type( $id ) ) { throw new \RuntimeException( 'media_action_source' ); } $draft = Media_Draft::get( $id, 'compress' ); echo '
' . esc_html__( 'Back to library', 'affstackdev-image-manager' ) . '

' . esc_html__( 'Make a smaller copy of a PDF', 'affstackdev-image-manager' ) . '

' . esc_html( get_the_title( $id ) ) . '

'; echo '

' . esc_html__( 'Ghostscript on this server writes a smaller copy, Image Manager checks it, and you look at it before it is saved as a new media item. The PDF itself is never changed, and pages that link to it keep showing it.', 'affstackdev-image-manager' ) . '

' . esc_html__( 'Open the PDF', 'affstackdev-image-manager' ) . '

'; if ( $draft && 'saved' === $draft['state'] ) { /* translators: %d: attachment ID of the new PDF. */ echo '

' . esc_html( sprintf( __( 'Smaller copy saved as media #%d.', 'affstackdev-image-manager' ), (int) $draft['result'] ) ) . ' ' . esc_html__( 'Open attachment', 'affstackdev-image-manager' ) . '

'; } elseif ( $draft && 'prepared' === $draft['state'] ) { $r = $draft['recipe']; $saving = 100 * ( 1 - (int) $r['copy_bytes'] / max( 1, (int) $r['bytes'] ) ); echo '

' /* translators: 1: the PDF's size; 2: the copy's size; 3: the saving in per cent; 4: number of pages. */ . esc_html( sprintf( __( 'The copy is %2$s instead of %1$s (%3$s%% smaller). It has all %4$d pages, the same text, links, comments and bookmarks, and each page looks the same at a small size.', 'affstackdev-image-manager' ), size_format( (int) $r['bytes'] ), size_format( (int) $r['copy_bytes'] ), number_format_i18n( $saving, 0 ), (int) $r['pages'] ) ) . ( 'small' === $r['preset'] ? ' ' . esc_html__( 'With the Smaller setting its pictures can look a little softer: open the copy and check it.', 'affstackdev-image-manager' ) : '' ) . '

'; echo '

' . esc_html__( 'Open the copy’s private preview', 'affstackdev-image-manager' ) . '

'; if ( time() - (int) $draft['created'] < DAY_IN_SECONDS ) { $begin( 'pdf_copy_save' ); echo ''; } else { echo '

' . esc_html__( 'This preview has expired. Prepare a fresh preview to continue.', 'affstackdev-image-manager' ) . '

'; } $begin( 'media_draft_discard' ); echo ''; } if ( ! $draft || 'prepared' !== $draft['state'] ) { if ( ! PDF_Copy::available() ) { echo '

' . esc_html__( 'This server has no Ghostscript that Image Manager can run, so it cannot make smaller copies of PDF files here. PDF browsing, organization and downloads remain available.', 'affstackdev-image-manager' ) . '

'; } else { $begin( 'pdf_copy_prepare' ); echo '

' . esc_html__( 'Up to 300 pages and a 64 MiB file. A PDF with a password, form fields, a signature, attached files, scripts, layers or multimedia is kept as it is, because a rewritten copy could lose those parts. No file is sent to an external service.', 'affstackdev-image-manager' ) . '

'; } } echo '
'; } /** * The words for a media change's reason code. * * @param string $code The reason code. * @return string The translated words. */ public static function human_error( string $code ): string { $messages = array( 'media_pdf_copy_preset' => __( 'Choose High quality or Smaller.', 'affstackdev-image-manager' ), 'media_pdf_copy_backend' => __( 'Ghostscript could not write a copy of this PDF on this server. The PDF is unchanged.', 'affstackdev-image-manager' ), 'media_pdf_copy_limits' => __( 'This PDF has more than 300 pages, more than Image Manager copies in one step. The PDF is unchanged.', 'affstackdev-image-manager' ), 'media_pdf_copy_no_saving' => __( 'A copy with this setting would not be smaller by the minimum saving, so none was made. The PDF is unchanged.', 'affstackdev-image-manager' ), 'media_pdf_copy_changed' => __( 'The copy did not pass the checks (the same pages, text, links, comments and bookmarks, and each page looking the same at a small size), so it was not kept. The PDF is unchanged.', 'affstackdev-image-manager' ), 'media_pdf_copy_encrypted' => __( 'This PDF is protected with a password, so no copy is made. The PDF is unchanged.', 'affstackdev-image-manager' ), 'media_pdf_copy_form' => __( 'This PDF has form fields, which a rewritten copy could lose, so no copy is made. The PDF is unchanged.', 'affstackdev-image-manager' ), 'media_pdf_copy_signature' => __( 'This PDF is signed, and a copy would no longer carry a valid signature, so no copy is made. The PDF is unchanged.', 'affstackdev-image-manager' ), 'media_pdf_copy_attachment' => __( 'This PDF has files attached to it, which a rewritten copy could lose, so no copy is made. The PDF is unchanged.', 'affstackdev-image-manager' ), 'media_pdf_copy_script' => __( 'This PDF has scripts, which a rewritten copy could lose, so no copy is made. The PDF is unchanged.', 'affstackdev-image-manager' ), 'media_pdf_copy_layers' => __( 'This PDF has layers that can be shown or hidden, which a rewritten copy could lose, so no copy is made. The PDF is unchanged.', 'affstackdev-image-manager' ), 'media_pdf_copy_multimedia' => __( 'This PDF has sound, video or 3D content, which a rewritten copy could lose, so no copy is made. The PDF is unchanged.', 'affstackdev-image-manager' ), 'media_draft_missing' => __( 'This preview is missing, changed, or belongs to another administrator. Reload the screen and prepare a fresh preview.', 'affstackdev-image-manager' ), 'media_draft_expired' => __( 'This preview has expired. Discard it and prepare a new one.', 'affstackdev-image-manager' ), 'media_draft_write' => __( 'The preview or its saved checkpoint could not be verified. Reload this screen to check its saved status.', 'affstackdev-image-manager' ), 'media_pdf_confirm' => __( 'Confirm the PDF operation before continuing.', 'affstackdev-image-manager' ), 'media_pdf_limits' => __( 'Choose one page from 1–500 and an output edge from 320–2560 pixels. Very large PDF pages cannot be rendered here.', 'affstackdev-image-manager' ), 'media_pdf_invalid' => __( 'This file is not a readable PDF document.', 'affstackdev-image-manager' ), 'media_pdf_backend' => __( 'This page could not be rendered. Check the page number, password protection, and the host’s Imagick/Ghostscript PDF policy and resource limits. The PDF is unchanged.', 'affstackdev-image-manager' ), 'media_pdf_metadata' => __( 'The new image was created, but its sizes or organization did not finish. Retry the same preview to finish the saved image without creating another.', 'affstackdev-image-manager' ), 'media_replace_confirm' => __( 'Review and confirm this replacement or recovery operation.', 'affstackdev-image-manager' ), 'media_replace_type' => __( 'The replacement must be a valid image in the same format as the current attachment.', 'affstackdev-image-manager' ), 'media_replace_backend' => __( 'The host could not create and verify all required image sizes. The current attachment has not been switched.', 'affstackdev-image-manager' ), 'media_replace_sizes' => __( 'This image family exceeds the supported size or count limits. Use a smaller image or fewer registered image sizes.', 'affstackdev-image-manager' ), 'media_replace_recovery' => __( 'A replacement checkpoint needs attention. Reload Replacement recovery and use the recovery control before preparing another change.', 'affstackdev-image-manager' ), 'media_replace_old_changed' => __( 'The attachment or its previous files changed after replacement. Undo will not overwrite those changes. Inspect the recovery ZIP under Backups.', 'affstackdev-image-manager' ), ); return $messages[ $code ] ?? __( 'The media operation could not finish. Reload its saved status before trying again.', 'affstackdev-image-manager' ); } }