Fixed low resolution for cached images.
Regenerate the image cache if a larger jpeg2000 image is requested.
It is the correction of the error that occurred in this
change - https://pdfium-review.googlesource.com/c/pdfium/+/99970
Bug: pdfium:1924,chromium:1408476
Change-Id: I9fd2769ea480c24fab99ee80244ea24764aa9ada
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/103150
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/page/BUILD.gn b/core/fpdfapi/page/BUILD.gn
index 79aeda5..51b4adf 100644
--- a/core/fpdfapi/page/BUILD.gn
+++ b/core/fpdfapi/page/BUILD.gn
@@ -141,6 +141,7 @@
"cpdf_colorspace_unittest.cpp",
"cpdf_devicecs_unittest.cpp",
"cpdf_function_unittest.cpp",
+ "cpdf_pageimagecache_unittest.cpp",
"cpdf_pageobjectholder_unittest.cpp",
"cpdf_psengine_unittest.cpp",
"cpdf_streamcontentparser_unittest.cpp",
@@ -149,6 +150,7 @@
deps = [
":page",
"../parser",
+ "../render",
]
pdfium_root_dir = "../../../"
}
diff --git a/core/fpdfapi/page/cpdf_pageimagecache.cpp b/core/fpdfapi/page/cpdf_pageimagecache.cpp
index 63a1ad6..ae8f72e 100644
--- a/core/fpdfapi/page/cpdf_pageimagecache.cpp
+++ b/core/fpdfapi/page/cpdf_pageimagecache.cpp
@@ -176,7 +176,7 @@
CPDF_ColorSpace::Family eFamily,
bool bLoadMask,
const CFX_Size& max_size_required) {
- if (m_pCachedBitmap) {
+ if (m_pCachedBitmap && IsCacheValid(max_size_required)) {
m_pCurBitmap = m_pCachedBitmap;
m_pCurMask = m_pCachedMask;
return CPDF_DIB::LoadState::kSuccess;
@@ -186,6 +186,8 @@
CPDF_DIB::LoadState ret = m_pCurBitmap.AsRaw<CPDF_DIB>()->StartLoadDIBBase(
true, pFormResources, pPageResources, bStdCS, eFamily, bLoadMask,
max_size_required);
+ m_bCachedSetMaxSizeRequired =
+ (max_size_required.width != 0 && max_size_required.height != 0);
if (ret == CPDF_DIB::LoadState::kContinue)
return CPDF_DIB::LoadState::kContinue;
@@ -238,3 +240,16 @@
if (m_pCachedMask)
m_dwCacheSize += m_pCachedMask->GetEstimatedImageMemoryBurden();
}
+
+bool CPDF_PageImageCache::Entry::IsCacheValid(
+ const CFX_Size& max_size_required) const {
+ if (!m_bCachedSetMaxSizeRequired) {
+ return true;
+ }
+ if (max_size_required.width == 0 && max_size_required.height == 0) {
+ return false;
+ }
+
+ return (m_pCachedBitmap->GetWidth() >= max_size_required.width) &&
+ (m_pCachedBitmap->GetHeight() >= max_size_required.height);
+}
diff --git a/core/fpdfapi/page/cpdf_pageimagecache.h b/core/fpdfapi/page/cpdf_pageimagecache.h
index 82702c5..5184ff6 100644
--- a/core/fpdfapi/page/cpdf_pageimagecache.h
+++ b/core/fpdfapi/page/cpdf_pageimagecache.h
@@ -80,6 +80,7 @@
private:
void ContinueGetCachedBitmap(CPDF_PageImageCache* pPageImageCache);
void CalcSize();
+ bool IsCacheValid(const CFX_Size& max_size_required) const;
uint32_t m_dwTimeCount = 0;
uint32_t m_MatteColor = 0;
@@ -89,6 +90,7 @@
RetainPtr<CFX_DIBBase> m_pCurMask;
RetainPtr<CFX_DIBBase> m_pCachedBitmap;
RetainPtr<CFX_DIBBase> m_pCachedMask;
+ bool m_bCachedSetMaxSizeRequired = false;
};
void ClearImageCacheEntry(const CPDF_Stream* pStream);
diff --git a/core/fpdfapi/page/cpdf_pageimagecache_unittest.cpp b/core/fpdfapi/page/cpdf_pageimagecache_unittest.cpp
new file mode 100644
index 0000000..34e436f
--- /dev/null
+++ b/core/fpdfapi/page/cpdf_pageimagecache_unittest.cpp
@@ -0,0 +1,81 @@
+// Copyright 2023 The PDFium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/fpdfapi/page/cpdf_pageimagecache.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "core/fpdfapi/page/cpdf_docpagedata.h"
+#include "core/fpdfapi/page/cpdf_image.h"
+#include "core/fpdfapi/page/cpdf_imageobject.h"
+#include "core/fpdfapi/page/cpdf_page.h"
+#include "core/fpdfapi/page/cpdf_pagemodule.h"
+#include "core/fpdfapi/parser/cpdf_parser.h"
+#include "core/fpdfapi/render/cpdf_docrenderdata.h"
+#include "core/fxcrt/fx_stream.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/utils/path_service.h"
+
+TEST(CPDFPageImageCache, RenderBug1924) {
+ // If you render a page with a JPEG2000 image as a thumbnail (small picture)
+ // first, the image that gets cached has a low resolution. If you afterwards
+ // render it full-size, you should get a larger image - the image cache will
+ // be regenerate.
+
+ CPDF_PageModule::Create();
+ {
+ std::string file_path;
+ ASSERT_TRUE(PathService::GetTestFilePath("jpx_lzw.pdf", &file_path));
+ auto document =
+ std::make_unique<CPDF_Document>(std::make_unique<CPDF_DocRenderData>(),
+ std::make_unique<CPDF_DocPageData>());
+ ASSERT_EQ(document->LoadDoc(
+ IFX_SeekableReadStream::CreateFromFilename(file_path.c_str()),
+ nullptr),
+ CPDF_Parser::SUCCESS);
+
+ RetainPtr<CPDF_Dictionary> page_dict =
+ document->GetMutablePageDictionary(0);
+ ASSERT_TRUE(page_dict);
+ auto page =
+ pdfium::MakeRetain<CPDF_Page>(document.get(), std::move(page_dict));
+ page->AddPageImageCache();
+ page->ParseContent();
+
+ CPDF_PageImageCache* page_image_cache = page->GetPageImageCache();
+ ASSERT_TRUE(page_image_cache);
+
+ CPDF_PageObject* page_obj = page->GetPageObjectByIndex(0);
+ ASSERT_TRUE(page_obj);
+ CPDF_ImageObject* image = page_obj->AsImage();
+ ASSERT_TRUE(image);
+
+ // Render with small scale.
+ bool should_continue = page_image_cache->StartGetCachedBitmap(
+ image->GetImage(), nullptr, page->GetMutablePageResources(), true,
+ CPDF_ColorSpace::Family::kICCBased, false, {50, 50});
+ while (should_continue)
+ should_continue = page_image_cache->Continue(nullptr);
+
+ RetainPtr<CFX_DIBBase> bitmap_small = page_image_cache->DetachCurBitmap();
+
+ // And render with large scale.
+ should_continue = page_image_cache->StartGetCachedBitmap(
+ image->GetImage(), nullptr, page->GetMutablePageResources(), true,
+ CPDF_ColorSpace::Family::kICCBased, false, {100, 100});
+ while (should_continue)
+ should_continue = page_image_cache->Continue(nullptr);
+
+ RetainPtr<CFX_DIBBase> bitmap_large = page_image_cache->DetachCurBitmap();
+
+ ASSERT_GT(bitmap_large->GetWidth(), bitmap_small->GetWidth());
+ ASSERT_GT(bitmap_large->GetHeight(), bitmap_small->GetHeight());
+
+ ASSERT_TRUE(page->AsPDFPage());
+ page->AsPDFPage()->ClearView();
+ }
+ CPDF_PageModule::Destroy();
+}