A fork of https://github.com/crosspoint-reader/crosspoint-reader
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: Scale cover images up if they're smaller than the device resolution (#964)

## Summary

**What is the goal of this PR?**
* Implement feature request
[#954](https://github.com/crosspoint-reader/crosspoint-reader/issues/954)
* Ensure cover images are scaled up to match the dimensions of the
screen, as well as scaled down

**What changes are included?**
* Naïve implementation for scaling up the source image

## Additional Context

If you find the extra comments to be excessive I can pare them back.

Edit: Fixed title

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**< YES >**_

authored by

Sam Lord and committed by
GitHub
6527f43c eb241ab3

+33 -17
+18 -11
lib/JpegToBmpConverter/JpegToBmpConverter.cpp
··· 236 236 uint32_t scaleY_fp = 65536; 237 237 bool needsScaling = false; 238 238 239 - if (targetWidth > 0 && targetHeight > 0 && (imageInfo.m_width > targetWidth || imageInfo.m_height > targetHeight)) { 240 - // Calculate scale to fit within target dimensions while maintaining aspect ratio 239 + if (targetWidth > 0 && targetHeight > 0 && (imageInfo.m_width != targetWidth || imageInfo.m_height != targetHeight)) { 240 + // Calculate scale to fit/fill target dimensions while maintaining aspect ratio 241 241 const float scaleToFitWidth = static_cast<float>(targetWidth) / imageInfo.m_width; 242 242 const float scaleToFitHeight = static_cast<float>(targetHeight) / imageInfo.m_height; 243 243 // We scale to the smaller dimension, so we can potentially crop later. ··· 261 261 scaleY_fp = (static_cast<uint32_t>(imageInfo.m_height) << 16) / outHeight; 262 262 needsScaling = true; 263 263 264 - LOG_DBG("JPG", "Pre-scaling %dx%d -> %dx%d (fit to %dx%d)", imageInfo.m_width, imageInfo.m_height, outWidth, 265 - outHeight, targetWidth, targetHeight); 264 + LOG_DBG("JPG", "Scaling %dx%d -> %dx%d (target %dx%d)", imageInfo.m_width, imageInfo.m_height, outWidth, outHeight, 265 + targetWidth, targetHeight); 266 266 } 267 267 268 268 // Write BMP header with output dimensions ··· 466 466 rowCount[outX] += count; 467 467 } 468 468 469 - // Check if we've crossed into the next output row 469 + // Check if we've crossed into the next output row(s) 470 470 // Current source Y in fixed point: y << 16 471 471 const uint32_t srcY_fp = static_cast<uint32_t>(y + 1) << 16; 472 472 473 - // Output row when source Y crosses the boundary 474 - if (srcY_fp >= nextOutY_srcStart && currentOutY < outHeight) { 473 + // Output all rows whose boundaries we've crossed (handles both up and downscaling) 474 + // For upscaling, one source row may produce multiple output rows 475 + while (srcY_fp >= nextOutY_srcStart && currentOutY < outHeight) { 475 476 memset(rowBuffer, 0, bytesPerRow); 476 477 477 478 if (USE_8BIT_OUTPUT && !oneBit) { ··· 516 517 bmpOut.write(rowBuffer, bytesPerRow); 517 518 currentOutY++; 518 519 519 - // Reset accumulators for next output row 520 - memset(rowAccum, 0, outWidth * sizeof(uint32_t)); 521 - memset(rowCount, 0, outWidth * sizeof(uint16_t)); 522 - 523 520 // Update boundary for next output row 524 521 nextOutY_srcStart = static_cast<uint32_t>(currentOutY + 1) * scaleY_fp; 522 + 523 + // For upscaling: don't reset accumulators if next output row uses same source data 524 + // Only reset when we'll move to a new source row 525 + if (srcY_fp >= nextOutY_srcStart) { 526 + // More output rows to emit from same source - keep accumulator data 527 + continue; 528 + } 529 + // Moving to next source row - reset accumulators 530 + memset(rowAccum, 0, outWidth * sizeof(uint32_t)); 531 + memset(rowCount, 0, outWidth * sizeof(uint16_t)); 525 532 } 526 533 } 527 534 }
+15 -6
lib/PngToBmpConverter/PngToBmpConverter.cpp
··· 603 603 bool needsScaling = false; 604 604 605 605 if (targetWidth > 0 && targetHeight > 0 && 606 - (static_cast<int>(width) > targetWidth || static_cast<int>(height) > targetHeight)) { 606 + (static_cast<int>(width) != targetWidth || static_cast<int>(height) != targetHeight)) { 607 607 const float scaleToFitWidth = static_cast<float>(targetWidth) / width; 608 608 const float scaleToFitHeight = static_cast<float>(targetHeight) / height; 609 609 float scale = 1.0; ··· 622 622 scaleY_fp = (static_cast<uint32_t>(height) << 16) / outHeight; 623 623 needsScaling = true; 624 624 625 - LOG_DBG("PNG", "Pre-scaling %ux%u -> %dx%d (fit to %dx%d)", width, height, outWidth, outHeight, targetWidth, 625 + LOG_DBG("PNG", "Scaling %ux%u -> %dx%d (target %dx%d)", width, height, outWidth, outHeight, targetWidth, 626 626 targetHeight); 627 627 } 628 628 ··· 767 767 rowCount[outX] += count; 768 768 } 769 769 770 - // Check if we've crossed into the next output row 770 + // Check if we've crossed into the next output row(s) 771 771 const uint32_t srcY_fp = static_cast<uint32_t>(y + 1) << 16; 772 772 773 - if (srcY_fp >= nextOutY_srcStart && currentOutY < outHeight) { 773 + // Output all rows whose boundaries we've crossed (handles both up and downscaling) 774 + // For upscaling, one source row may produce multiple output rows 775 + while (srcY_fp >= nextOutY_srcStart && currentOutY < outHeight) { 774 776 memset(rowBuffer, 0, bytesPerRow); 775 777 776 778 if (USE_8BIT_OUTPUT && !oneBit) { ··· 812 814 bmpOut.write(rowBuffer, bytesPerRow); 813 815 currentOutY++; 814 816 817 + nextOutY_srcStart = static_cast<uint32_t>(currentOutY + 1) * scaleY_fp; 818 + 819 + // For upscaling: don't reset accumulators if next output row uses same source data 820 + // Only reset when we'll move to a new source row 821 + if (srcY_fp >= nextOutY_srcStart) { 822 + // More output rows to emit from same source - keep accumulator data 823 + continue; 824 + } 825 + // Moving to next source row - reset accumulators 815 826 memset(rowAccum, 0, outWidth * sizeof(uint32_t)); 816 827 memset(rowCount, 0, outWidth * sizeof(uint16_t)); 817 - 818 - nextOutY_srcStart = static_cast<uint32_t>(currentOutY + 1) * scaleY_fp; 819 828 } 820 829 } 821 830