| // Copyright 2020 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/services/printing/pdf_thumbnailer.h" |
| |
| #include <string.h> |
| #include <utility> |
| |
| #include "base/containers/span.h" |
| #include "base/logging.h" |
| #include "base/memory/shared_memory_mapping.h" |
| #include "pdf/pdf.h" |
| #include "third_party/skia/include/core/SkBitmap.h" |
| |
| namespace printing { |
| |
| namespace { |
| |
| // Whether or not to rotate PDF to fit the given size; always no. |
| constexpr bool kAutorotate = false; |
| |
| // Whether to create color thumbnails. Always yes. |
| constexpr bool kUseColor = true; |
| |
| } // namespace |
| |
| PdfThumbnailer::PdfThumbnailer() = default; |
| |
| PdfThumbnailer::~PdfThumbnailer() = default; |
| |
| void PdfThumbnailer::GetThumbnail(printing::mojom::ThumbParamsPtr params, |
| base::ReadOnlySharedMemoryRegion pdf_region, |
| GetThumbnailCallback callback) { |
| // Vet the requested thumbnail size. |
| int width_px = params->size_px.width(); |
| int height_px = params->size_px.height(); |
| if (params->size_px.IsEmpty() || width_px > PdfThumbnailer::kMaxWidth || |
| height_px > PdfThumbnailer::kMaxHeight) { |
| DLOG(ERROR) << "Invalid thumbnail size " << width_px << " x " << height_px; |
| std::move(callback).Run(SkBitmap()); |
| return; |
| } |
| |
| // Decode memory region as PDF bytes. |
| base::ReadOnlySharedMemoryMapping pdf_map = pdf_region.Map(); |
| if (!pdf_map.IsValid()) { |
| DLOG(ERROR) << "Failed to decode memory map for PDF thumbnail"; |
| std::move(callback).Run(SkBitmap()); |
| return; |
| } |
| auto pdf_buffer = pdf_map.GetMemoryAsSpan<const uint8_t>(); |
| |
| // Allocate bitmap to which we render the thumbnail. |
| SkBitmap result; |
| const SkImageInfo info = SkImageInfo::Make( |
| width_px, height_px, kBGRA_8888_SkColorType, kOpaque_SkAlphaType); |
| if (!result.tryAllocPixels(info, info.minRowBytes())) { |
| DLOG(ERROR) << "Failed to allocate bitmap pixels"; |
| std::move(callback).Run(SkBitmap()); |
| return; |
| } |
| |
| // Convert PDF bytes into a bitmap thumbnail. |
| chrome_pdf::RenderOptions options = { |
| .stretch_to_bounds = params->stretch, |
| .keep_aspect_ratio = params->keep_aspect, |
| .autorotate = kAutorotate, |
| .use_color = kUseColor, |
| .render_device_type = chrome_pdf::RenderDeviceType::kDisplay, |
| }; |
| if (!chrome_pdf::RenderPDFPageToBitmap(pdf_buffer, 0, result.getPixels(), |
| params->size_px, params->dpi, |
| options)) { |
| DLOG(ERROR) << "Failed to render PDF buffer as bitmap image"; |
| std::move(callback).Run(SkBitmap()); |
| return; |
| } |
| |
| DCHECK_EQ(width_px, result.width()); |
| DCHECK_EQ(height_px, result.height()); |
| std::move(callback).Run(result); |
| } |
| |
| } // namespace printing |