mirror of https://github.com/KLayout/klayout.git
WIP: layer icons now follow oversampling and high-resolution mode, new GSI method to fetch layer icon: LayoutView#icon_for_layer
This commit is contained in:
parent
00e78eb76c
commit
1bff5c1ac3
|
|
@ -30,6 +30,7 @@
|
||||||
#include "laySelector.h"
|
#include "laySelector.h"
|
||||||
#include "layFinder.h"
|
#include "layFinder.h"
|
||||||
#include "layLayerProperties.h"
|
#include "layLayerProperties.h"
|
||||||
|
#include "laybasicConfig.h"
|
||||||
#include "tlProgress.h"
|
#include "tlProgress.h"
|
||||||
#include "edtPlugin.h"
|
#include "edtPlugin.h"
|
||||||
#include "edtMainService.h"
|
#include "edtMainService.h"
|
||||||
|
|
|
||||||
|
|
@ -1603,6 +1603,17 @@ LAYBASIC_PUBLIC Class<lay::LayoutViewBase> decl_LayoutViewBase ("lay", "LayoutVi
|
||||||
"Returns an array of \\LayerPropertiesIterator objects pointing to the currently selected layers. "
|
"Returns an array of \\LayerPropertiesIterator objects pointing to the currently selected layers. "
|
||||||
"If no layer view is selected currently, an empty array is returned.\n"
|
"If no layer view is selected currently, an empty array is returned.\n"
|
||||||
) +
|
) +
|
||||||
|
gsi::method ("icon_for_layer", &lay::LayoutViewBase::icon_for_layer, gsi::arg ("iter"), gsi::arg ("w"), gsi::arg ("h"), gsi::arg ("dpr"), gsi::arg ("di_off", 0), gsi::arg ("no_state", false),
|
||||||
|
"@brief Creates an icon pixmap for the given layer.\n"
|
||||||
|
"\n"
|
||||||
|
"The icon will have size w times h pixels multiplied by the device pixel ratio (dpr). The dpr is "
|
||||||
|
"The number of physical pixels per logical pixels on high-DPI displays.\n"
|
||||||
|
"\n"
|
||||||
|
"'di_off' will shift the dither pattern by the given number of (physical) pixels. "
|
||||||
|
"If 'no_state' is true, the icon will not reflect visibility or validity states but rather the display style.\n"
|
||||||
|
"\n"
|
||||||
|
"This method has been introduced in version 0.28."
|
||||||
|
) +
|
||||||
gsi::event ("on_active_cellview_changed", static_cast<tl::Event (lay::LayoutViewBase::*)> (&lay::LayoutViewBase::active_cellview_changed_event),
|
gsi::event ("on_active_cellview_changed", static_cast<tl::Event (lay::LayoutViewBase::*)> (&lay::LayoutViewBase::active_cellview_changed_event),
|
||||||
"@brief An event indicating that the active cellview has changed\n"
|
"@brief An event indicating that the active cellview has changed\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
|
|
||||||
|
|
@ -131,137 +131,6 @@ std::string ImageCacheEntry::to_string () const
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
static void
|
|
||||||
blowup (const tl::PixelBuffer &src, tl::PixelBuffer &dest, unsigned int os)
|
|
||||||
{
|
|
||||||
unsigned int ymax = src.height ();
|
|
||||||
unsigned int xmax = src.width ();
|
|
||||||
|
|
||||||
for (unsigned int y = 0; y < ymax; ++y) {
|
|
||||||
for (unsigned int i = 0; i < os; ++i) {
|
|
||||||
const uint32_t *psrc = (const uint32_t *) src.scan_line (y);
|
|
||||||
uint32_t *pdest = (uint32_t *) dest.scan_line (y * os + i);
|
|
||||||
for (unsigned int x = 0; x < xmax; ++x) {
|
|
||||||
for (unsigned int j = 0; j < os; ++j) {
|
|
||||||
*pdest++ = *psrc;
|
|
||||||
}
|
|
||||||
++psrc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
subsample (const tl::PixelBuffer &src, tl::PixelBuffer &dest, unsigned int os, double g)
|
|
||||||
{
|
|
||||||
// TODO: this is probably not compatible with the endianess of SPARC ..
|
|
||||||
|
|
||||||
// LUT's for combining the RGB channels
|
|
||||||
|
|
||||||
// forward transformation table
|
|
||||||
unsigned short lut1[256];
|
|
||||||
for (unsigned int i = 0; i < 256; ++i) {
|
|
||||||
double f = (65536 / (os * os)) - 1;
|
|
||||||
lut1[i] = (unsigned short)std::min (f, std::max (0.0, floor (0.5 + pow (i / 255.0, g) * f)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// backward transformation table
|
|
||||||
unsigned char lut2[65536];
|
|
||||||
for (unsigned int i = 0; i < 65536; ++i) {
|
|
||||||
double f = os * os * ((65536 / (os * os)) - 1);
|
|
||||||
lut2[i] = (unsigned char)std::min (255.0, std::max (0.0, floor (0.5 + pow (i / f, 1.0 / g) * 255.0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// LUT's for alpha channel
|
|
||||||
|
|
||||||
// forward transformation table
|
|
||||||
unsigned short luta1[256];
|
|
||||||
for (unsigned int i = 0; i < 256; ++i) {
|
|
||||||
double f = (65536 / (os * os)) - 1;
|
|
||||||
luta1[i] = (unsigned short)std::min (f, std::max (0.0, floor (0.5 + (i / 255.0) * f)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// backward transformation table
|
|
||||||
unsigned char luta2[65536];
|
|
||||||
for (unsigned int i = 0; i < 65536; ++i) {
|
|
||||||
double f = os * os * ((65536 / (os * os)) - 1);
|
|
||||||
luta2[i] = (unsigned char)std::min (255.0, std::max (0.0, floor (0.5 + (i / f) * 255.0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int ymax = dest.height ();
|
|
||||||
unsigned int xmax = dest.width ();
|
|
||||||
|
|
||||||
unsigned short *buffer = new unsigned short[xmax * 4];
|
|
||||||
|
|
||||||
for (unsigned int y = 0; y < ymax; ++y) {
|
|
||||||
|
|
||||||
{
|
|
||||||
|
|
||||||
const unsigned char *psrc = (const unsigned char *) src.scan_line (y * os);
|
|
||||||
unsigned short *pdest = buffer;
|
|
||||||
|
|
||||||
for (unsigned int x = 0; x < xmax; ++x) {
|
|
||||||
|
|
||||||
pdest[0] = lut1[psrc[0]];
|
|
||||||
pdest[1] = lut1[psrc[1]];
|
|
||||||
pdest[2] = lut1[psrc[2]];
|
|
||||||
pdest[3] = luta1[psrc[3]];
|
|
||||||
psrc += 4;
|
|
||||||
|
|
||||||
for (unsigned int j = os; j > 1; j--) {
|
|
||||||
pdest[0] += lut1[psrc[0]];
|
|
||||||
pdest[1] += lut1[psrc[1]];
|
|
||||||
pdest[2] += lut1[psrc[2]];
|
|
||||||
pdest[3] += luta1[psrc[3]];
|
|
||||||
psrc += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
pdest += 4;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned int i = 1; i < os; ++i) {
|
|
||||||
|
|
||||||
const unsigned char *psrc = (const unsigned char *) src.scan_line (y * os + i);
|
|
||||||
unsigned short *pdest = buffer;
|
|
||||||
|
|
||||||
for (unsigned int x = 0; x < xmax; ++x) {
|
|
||||||
|
|
||||||
for (unsigned int j = os; j > 0; j--) {
|
|
||||||
pdest[0] += lut1[psrc[0]];
|
|
||||||
pdest[1] += lut1[psrc[1]];
|
|
||||||
pdest[2] += lut1[psrc[2]];
|
|
||||||
pdest[3] += luta1[psrc[3]];
|
|
||||||
psrc += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
pdest += 4;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
|
|
||||||
unsigned char *pdest = (unsigned char *) dest.scan_line (y);
|
|
||||||
const unsigned short *psrc = buffer;
|
|
||||||
|
|
||||||
for (unsigned int x = 0; x < xmax; ++x) {
|
|
||||||
*pdest++ = lut2[*psrc++];
|
|
||||||
*pdest++ = lut2[*psrc++];
|
|
||||||
*pdest++ = lut2[*psrc++];
|
|
||||||
*pdest++ = luta2[*psrc++];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
delete[] buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
invert (unsigned char *data, unsigned int width, unsigned int height)
|
invert (unsigned char *data, unsigned int width, unsigned int height)
|
||||||
{
|
{
|
||||||
|
|
@ -693,7 +562,7 @@ LayoutCanvas::paint_event ()
|
||||||
} else {
|
} else {
|
||||||
tl::PixelBuffer subsampled_image (m_viewport.width (), m_viewport.height ());
|
tl::PixelBuffer subsampled_image (m_viewport.width (), m_viewport.height ());
|
||||||
subsampled_image.set_transparent (mp_image->transparent ());
|
subsampled_image.set_transparent (mp_image->transparent ());
|
||||||
subsample (full_image, subsampled_image, m_oversampling, m_gamma);
|
full_image.subsample (subsampled_image, m_oversampling, m_gamma);
|
||||||
*mp_image_fg = subsampled_image;
|
*mp_image_fg = subsampled_image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -705,7 +574,7 @@ LayoutCanvas::paint_event ()
|
||||||
|
|
||||||
tl::PixelBuffer subsampled_image (m_viewport.width (), m_viewport.height ());
|
tl::PixelBuffer subsampled_image (m_viewport.width (), m_viewport.height ());
|
||||||
subsampled_image.set_transparent (mp_image->transparent ());
|
subsampled_image.set_transparent (mp_image->transparent ());
|
||||||
subsample (*mp_image, subsampled_image, m_oversampling, m_gamma);
|
mp_image->subsample (subsampled_image, m_oversampling, m_gamma);
|
||||||
*mp_image_fg = subsampled_image;
|
*mp_image_fg = subsampled_image;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -744,7 +613,7 @@ LayoutCanvas::paint_event ()
|
||||||
} else {
|
} else {
|
||||||
tl::PixelBuffer subsampled_image (m_viewport.width (), m_viewport.height ());
|
tl::PixelBuffer subsampled_image (m_viewport.width (), m_viewport.height ());
|
||||||
subsampled_image.set_transparent (true);
|
subsampled_image.set_transparent (true);
|
||||||
subsample (full_image, subsampled_image, m_oversampling, m_gamma);
|
full_image.subsample (subsampled_image, m_oversampling, m_gamma);
|
||||||
QImage img = subsampled_image.to_image ();
|
QImage img = subsampled_image.to_image ();
|
||||||
#if QT_VERSION >= 0x050000
|
#if QT_VERSION >= 0x050000
|
||||||
img.setDevicePixelRatio (dpr ());
|
img.setDevicePixelRatio (dpr ());
|
||||||
|
|
@ -820,9 +689,9 @@ public:
|
||||||
{
|
{
|
||||||
if (mp_image_l) {
|
if (mp_image_l) {
|
||||||
unsigned int os = mp_image_l->width () / width;
|
unsigned int os = mp_image_l->width () / width;
|
||||||
blowup (*mp_image, *mp_image_l, os);
|
mp_image->blowup (*mp_image_l, os);
|
||||||
bitmaps_to_image (fg_view_op_vector (), fg_bitmap_vector (), dp, ls, 1.0 / resolution (), mp_image_l, mp_image_l->width (), mp_image_l->height (), false, 0);
|
bitmaps_to_image (fg_view_op_vector (), fg_bitmap_vector (), dp, ls, 1.0 / resolution (), mp_image_l, mp_image_l->width (), mp_image_l->height (), false, 0);
|
||||||
subsample (*mp_image_l, *mp_image, os, m_gamma);
|
mp_image_l->subsample (*mp_image, os, m_gamma);
|
||||||
} else {
|
} else {
|
||||||
bitmaps_to_image (fg_view_op_vector (), fg_bitmap_vector (), dp, ls, 1.0 / resolution (), mp_image, width, height, false, 0);
|
bitmaps_to_image (fg_view_op_vector (), fg_bitmap_vector (), dp, ls, 1.0 / resolution (), mp_image, width, height, false, 0);
|
||||||
}
|
}
|
||||||
|
|
@ -833,7 +702,7 @@ public:
|
||||||
{
|
{
|
||||||
if (mp_image_l && mp_image->width () > 0) {
|
if (mp_image_l && mp_image->width () > 0) {
|
||||||
unsigned int os = mp_image_l->width () / mp_image->width ();
|
unsigned int os = mp_image_l->width () / mp_image->width ();
|
||||||
subsample (*mp_image_l, *mp_image, os, m_gamma);
|
mp_image_l->subsample (*mp_image, os, m_gamma);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -257,10 +257,26 @@ public:
|
||||||
void set_oversampling (unsigned int os);
|
void set_oversampling (unsigned int os);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set high-resolution mode (utilize full DPI on high-DPI displays)
|
* @brief Gets the oversampling factor
|
||||||
|
*/
|
||||||
|
unsigned int oversampling () const
|
||||||
|
{
|
||||||
|
return m_oversampling;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set high resolution mode (utilize full DPI on high-DPI displays)
|
||||||
*/
|
*/
|
||||||
void set_highres_mode (bool hrm);
|
void set_highres_mode (bool hrm);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the high resolution mode flag
|
||||||
|
*/
|
||||||
|
bool highres_mode () const
|
||||||
|
{
|
||||||
|
return m_hrm;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sets the depth of the image cache
|
* @brief Sets the depth of the image cache
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@
|
||||||
#include "tlExceptions.h"
|
#include "tlExceptions.h"
|
||||||
#include "tlDeferredExecution.h"
|
#include "tlDeferredExecution.h"
|
||||||
#include "layLayoutViewBase.h"
|
#include "layLayoutViewBase.h"
|
||||||
|
#include "layBitmapsToImage.h"
|
||||||
#include "layViewOp.h"
|
#include "layViewOp.h"
|
||||||
#include "layViewObject.h"
|
#include "layViewObject.h"
|
||||||
#include "layConverters.h"
|
#include "layConverters.h"
|
||||||
|
|
@ -1527,6 +1528,181 @@ LayoutViewBase::set_selected_layers (const std::vector<lay::LayerPropertiesConst
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A helper function to create an image from a single bitmap
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
single_bitmap_to_image (const lay::ViewOp &view_op, lay::Bitmap &bitmap,
|
||||||
|
tl::PixelBuffer *pimage, const lay::DitherPattern &dither_pattern, const lay::LineStyles &line_styles,
|
||||||
|
double dpr, unsigned int width, unsigned int height)
|
||||||
|
{
|
||||||
|
std::vector <lay::ViewOp> view_ops;
|
||||||
|
view_ops.push_back (view_op);
|
||||||
|
|
||||||
|
std::vector <lay::Bitmap *> pbitmaps;
|
||||||
|
pbitmaps.push_back (&bitmap);
|
||||||
|
|
||||||
|
lay::bitmaps_to_image (view_ops, pbitmaps, dither_pattern, line_styles, dpr, pimage, width, height, false, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
tl::PixelBuffer
|
||||||
|
LayoutViewBase::icon_for_layer (const LayerPropertiesConstIterator &iter, unsigned int w, unsigned int h, double dpr, unsigned int di_off, bool no_state)
|
||||||
|
{
|
||||||
|
int oversampling = canvas () ? canvas ()->oversampling () : 1;
|
||||||
|
double gamma = 2.0;
|
||||||
|
|
||||||
|
bool hrm = canvas () ? canvas ()->highres_mode () : false;
|
||||||
|
double dpr_drawing = oversampling * (hrm ? 1.0 : dpr);
|
||||||
|
|
||||||
|
h = std::max ((unsigned int) 16, h) * oversampling * dpr + 0.5;
|
||||||
|
w = std::max ((unsigned int) 16, w) * oversampling * dpr + 0.5;
|
||||||
|
|
||||||
|
tl::color_t def_color = 0x808080;
|
||||||
|
tl::color_t fill_color = iter->has_fill_color (true) ? iter->eff_fill_color (true) : def_color;
|
||||||
|
tl::color_t frame_color = iter->has_frame_color (true) ? iter->eff_frame_color (true) : def_color;
|
||||||
|
|
||||||
|
tl::PixelBuffer image (w, h);
|
||||||
|
image.set_transparent (true);
|
||||||
|
image.fill (background_color ().rgb ());
|
||||||
|
|
||||||
|
// upper scanline is a dummy one
|
||||||
|
tl::color_t *sl0 = (uint32_t *) image.scan_line (0);
|
||||||
|
for (size_t i = 0; i < w; ++i) {
|
||||||
|
*sl0++ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lay::Bitmap fill (w, h, 1.0);
|
||||||
|
lay::Bitmap frame (w, h, 1.0);
|
||||||
|
lay::Bitmap text (w, h, 1.0);
|
||||||
|
lay::Bitmap vertex (w, h, 1.0);
|
||||||
|
|
||||||
|
unsigned int wp = w - 1;
|
||||||
|
|
||||||
|
if (! no_state && ! iter->visible (true)) {
|
||||||
|
|
||||||
|
wp = w / 4;
|
||||||
|
|
||||||
|
// Show the arrow if it is invisible also locally.
|
||||||
|
if (! iter->visible (false)) {
|
||||||
|
|
||||||
|
unsigned int aw = h / 4;
|
||||||
|
unsigned int ap = w / 2 - 1;
|
||||||
|
for (unsigned int i = 0; i <= aw; ++i) {
|
||||||
|
text.fill (h / 2 - 1 - i, ap, ap + aw - i + 1);
|
||||||
|
text.fill (h / 2 - 1 + i, ap, ap + aw - i + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! no_state && no_stipples ()) {
|
||||||
|
// Show a partial stipple pattern only for "no stipple" mode
|
||||||
|
for (unsigned int i = 1; i < h - 2; ++i) {
|
||||||
|
fill.fill (i, w - 1 - w / 4, w);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (unsigned int i = 1; i < h - 2; ++i) {
|
||||||
|
fill.fill (i, w - 1 - wp, w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int lw = iter->width (true);
|
||||||
|
if (lw < 0) {
|
||||||
|
// default line width is 0 for parents and 1 for leafs
|
||||||
|
lw = iter->has_children () ? 0 : 1;
|
||||||
|
}
|
||||||
|
lw = lw * dpr_drawing + 0.5;
|
||||||
|
|
||||||
|
int p0 = lw / 2;
|
||||||
|
p0 = std::max (0, std::min (int (w / 4 - 1), p0));
|
||||||
|
|
||||||
|
int p1 = (lw - 1) / 2;
|
||||||
|
p1 = std::max (0, std::min (int (w / 4 - 1), p1));
|
||||||
|
|
||||||
|
int p0x = p0, p1x = p1;
|
||||||
|
unsigned int ddx = 0;
|
||||||
|
unsigned int ddy = h - 2 - p1 - p0;
|
||||||
|
if (iter->xfill (true)) {
|
||||||
|
ddx = wp - p0 - p1 - 1;
|
||||||
|
}
|
||||||
|
unsigned int d = ddx / 2;
|
||||||
|
|
||||||
|
frame.fill (p0, w - 1 - (wp - p1), w);
|
||||||
|
frame.fill (h - 2 - p1, w - 1 - (wp - p1), w);
|
||||||
|
|
||||||
|
for (unsigned int i = p0; i < h - 2; ++i) {
|
||||||
|
|
||||||
|
frame.fill (i, w - 1 - p0, w - p0);
|
||||||
|
frame.fill (i, w - 1 - (wp - p1), w - (wp - p1));
|
||||||
|
frame.fill (i, w - 1 - p0x, w - p0x);
|
||||||
|
frame.fill (i, w - 1 - (wp - p1x), w - (wp - p1x));
|
||||||
|
|
||||||
|
while (d < ddx) {
|
||||||
|
d += ddy;
|
||||||
|
frame.fill (i, w - 1 - p0x, w - p0x);
|
||||||
|
frame.fill (i, w - 1 - (wp - p1x), w - (wp - p1x));
|
||||||
|
++p0x;
|
||||||
|
++p1x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d >= ddx) {
|
||||||
|
d -= ddx;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! no_state && ! iter->valid (true)) {
|
||||||
|
|
||||||
|
unsigned int bp = w - 1 - ((w * 7) / 8 - 1);
|
||||||
|
unsigned int be = bp + h / 2;
|
||||||
|
unsigned int bw = h / 4 - 1;
|
||||||
|
unsigned int by = h / 2 - 1;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < bw + 2; ++i) {
|
||||||
|
fill.clear (by - i, bp - 1, be);
|
||||||
|
fill.clear (by + i, bp - 1, be);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < bw; ++i) {
|
||||||
|
text.fill (by - i, bp + bw - i - 1, bp + bw - i + 1);
|
||||||
|
text.fill (by - i - 1, bp + bw - i - 1, bp + bw - i + 1);
|
||||||
|
text.fill (by - i, bp + bw + i, bp + bw + i + 2);
|
||||||
|
text.fill (by - i - 1, bp + bw + i, bp + bw + i + 2);
|
||||||
|
text.fill (by + i, bp + bw - i - 1, bp + bw - i + 1);
|
||||||
|
text.fill (by + i + 1, bp + bw - i - 1, bp + bw - i + 1);
|
||||||
|
text.fill (by + i, bp + bw + i, bp + bw + i + 2);
|
||||||
|
text.fill (by + i + 1, bp + bw + i, bp + bw + i + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
vertex.fill (h / 2 - 1, w - 1 - wp / 2, w - wp / 2);
|
||||||
|
|
||||||
|
lay::ViewOp::Mode mode = lay::ViewOp::Copy;
|
||||||
|
|
||||||
|
// create fill
|
||||||
|
single_bitmap_to_image (lay::ViewOp (fill_color, mode, 0, iter->eff_dither_pattern (true), di_off), fill, &image, dither_pattern (), line_styles (), dpr_drawing, w, h);
|
||||||
|
// create frame
|
||||||
|
if (lw == 0) {
|
||||||
|
single_bitmap_to_image (lay::ViewOp (frame_color, mode, 0 /*solid line*/, 2 /*dotted*/, 0), frame, &image, dither_pattern (), line_styles (), dpr_drawing, w, h);
|
||||||
|
} else {
|
||||||
|
single_bitmap_to_image (lay::ViewOp (frame_color, mode, iter->eff_line_style (true), 0, 0, lay::ViewOp::Rect, lw), frame, &image, dither_pattern (), line_styles (), dpr_drawing, w, h);
|
||||||
|
}
|
||||||
|
// create text
|
||||||
|
single_bitmap_to_image (lay::ViewOp (frame_color, mode, 0, 0, 0), text, &image, dither_pattern (), line_styles (), dpr_drawing, w, h);
|
||||||
|
// create vertex
|
||||||
|
single_bitmap_to_image (lay::ViewOp (frame_color, mode, 0, 0, 0, lay::ViewOp::Cross, iter->marked (true) ? 9/*mark size*/ : 0), vertex, &image, dither_pattern (), line_styles (), dpr_drawing, w, h);
|
||||||
|
|
||||||
|
if (oversampling > 1) {
|
||||||
|
tl::PixelBuffer subsampled (image.width () / oversampling, image.height () / oversampling);
|
||||||
|
image.subsample (subsampled, oversampling, gamma);
|
||||||
|
return subsampled;
|
||||||
|
} else {
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LayoutViewBase::merge_dither_pattern (lay::LayerPropertiesList &props)
|
LayoutViewBase::merge_dither_pattern (lay::LayerPropertiesList &props)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -581,6 +581,18 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual std::vector<lay::LayerPropertiesConstIterator> selected_layers () const;
|
virtual std::vector<lay::LayerPropertiesConstIterator> selected_layers () const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets a pixmap representing the given layer
|
||||||
|
*
|
||||||
|
* @param iter indicates the layer
|
||||||
|
* @param w The width in logical pixels of the generated pixmap (will be multiplied by dpr)
|
||||||
|
* @param h The height in logical pixels of the generated pixmap (will be multiplied by dpr)
|
||||||
|
* @param dpr The device pixel ratio (number of image pixes per logical pixel)
|
||||||
|
* @param di_off The dither pattern offset (used for animation)
|
||||||
|
* @param no_state If true, the state will not be indicated
|
||||||
|
*/
|
||||||
|
tl::PixelBuffer icon_for_layer (const lay::LayerPropertiesConstIterator &iter, unsigned int w, unsigned int h, double dpr, unsigned int di_off, bool no_state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sets the layers that are selected in the layer browser
|
* @brief Sets the layers that are selected in the layer browser
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -208,6 +208,8 @@ LayerControlPanel::LayerControlPanel (lay::LayoutViewBase *view, db::Manager *ma
|
||||||
m_hidden_flags_need_update (true),
|
m_hidden_flags_need_update (true),
|
||||||
m_in_update (false),
|
m_in_update (false),
|
||||||
m_phase (0),
|
m_phase (0),
|
||||||
|
m_oversampling (1),
|
||||||
|
m_hrm (false),
|
||||||
m_do_update_content_dm (this, &LayerControlPanel::do_update_content),
|
m_do_update_content_dm (this, &LayerControlPanel::do_update_content),
|
||||||
m_no_stipples (false)
|
m_no_stipples (false)
|
||||||
{
|
{
|
||||||
|
|
@ -1712,6 +1714,24 @@ LayerControlPanel::set_phase (int phase)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LayerControlPanel::set_highres_mode (bool hrm)
|
||||||
|
{
|
||||||
|
if (m_hrm != hrm) {
|
||||||
|
m_hrm = hrm;
|
||||||
|
m_do_update_content_dm ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LayerControlPanel::set_oversampling (int os)
|
||||||
|
{
|
||||||
|
if (m_oversampling != os) {
|
||||||
|
m_oversampling = os;
|
||||||
|
m_do_update_content_dm ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
set_hidden_flags_rec (LayerTreeModel *model, QTreeView *tree_view, const QModelIndex &parent)
|
set_hidden_flags_rec (LayerTreeModel *model, QTreeView *tree_view, const QModelIndex &parent)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -208,6 +208,16 @@ public:
|
||||||
*/
|
*/
|
||||||
void set_phase (int phase);
|
void set_phase (int phase);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets highres mode
|
||||||
|
*/
|
||||||
|
void set_highres_mode (bool hrm);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets oversampling mode
|
||||||
|
*/
|
||||||
|
void set_oversampling (int os);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Tell, if the model has been updated already (true) or if it is still under construction (false)
|
* @brief Tell, if the model has been updated already (true) or if it is still under construction (false)
|
||||||
*/
|
*/
|
||||||
|
|
@ -347,6 +357,8 @@ private:
|
||||||
bool m_in_update;
|
bool m_in_update;
|
||||||
std::vector<size_t> m_new_sel;
|
std::vector<size_t> m_new_sel;
|
||||||
int m_phase;
|
int m_phase;
|
||||||
|
int m_oversampling;
|
||||||
|
bool m_hrm;
|
||||||
tl::DeferredMethod<LayerControlPanel> m_do_update_content_dm;
|
tl::DeferredMethod<LayerControlPanel> m_do_update_content_dm;
|
||||||
std::set<unsigned int> m_expanded;
|
std::set<unsigned int> m_expanded;
|
||||||
bool m_no_stipples;
|
bool m_no_stipples;
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@
|
||||||
|
|
||||||
#include "layLayerTreeModel.h"
|
#include "layLayerTreeModel.h"
|
||||||
#include "layLayoutViewBase.h"
|
#include "layLayoutViewBase.h"
|
||||||
#include "layBitmapsToImage.h"
|
|
||||||
#include "dbLayoutUtils.h"
|
#include "dbLayoutUtils.h"
|
||||||
#include "tlLog.h"
|
#include "tlLog.h"
|
||||||
#include "tlTimer.h"
|
#include "tlTimer.h"
|
||||||
|
|
@ -182,7 +181,8 @@ EmptyWithinViewCache::determine_empty_layers (const db::Layout *layout, unsigned
|
||||||
LayerTreeModel::LayerTreeModel (QWidget *parent, lay::LayoutViewBase *view)
|
LayerTreeModel::LayerTreeModel (QWidget *parent, lay::LayoutViewBase *view)
|
||||||
: QAbstractItemModel (parent),
|
: QAbstractItemModel (parent),
|
||||||
mp_parent (parent), mp_view (view), m_filter_mode (false), m_id_start (0), m_id_end (0),
|
mp_parent (parent), mp_view (view), m_filter_mode (false), m_id_start (0), m_id_end (0),
|
||||||
m_phase ((unsigned int) -1), m_test_shapes_in_view (false), m_hide_empty_layers (false)
|
m_phase ((unsigned int) -1),
|
||||||
|
m_test_shapes_in_view (false), m_hide_empty_layers (false)
|
||||||
{
|
{
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
@ -620,170 +620,11 @@ LayerTreeModel::empty_within_view_predicate (const QModelIndex &index) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A helper function to create an image from a single bitmap
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
single_bitmap_to_image (const lay::ViewOp &view_op, lay::Bitmap &bitmap,
|
|
||||||
tl::PixelBuffer *pimage, const lay::DitherPattern &dither_pattern, const lay::LineStyles &line_styles,
|
|
||||||
double dpr, unsigned int width, unsigned int height)
|
|
||||||
{
|
|
||||||
std::vector <lay::ViewOp> view_ops;
|
|
||||||
view_ops.push_back (view_op);
|
|
||||||
|
|
||||||
std::vector <lay::Bitmap *> pbitmaps;
|
|
||||||
pbitmaps.push_back (&bitmap);
|
|
||||||
|
|
||||||
lay::bitmaps_to_image (view_ops, pbitmaps, dither_pattern, line_styles, dpr, pimage, width, height, false, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
LAYUI_PUBLIC
|
|
||||||
QIcon
|
QIcon
|
||||||
LayerTreeModel::icon_for_layer (const lay::LayerPropertiesConstIterator &iter, lay::LayoutViewBase *view, unsigned int w, unsigned int h, double dpr, unsigned int di_off, bool no_state)
|
LayerTreeModel::icon_for_layer (const lay::LayerPropertiesConstIterator &iter, lay::LayoutViewBase *view, unsigned int w, unsigned int h, double dpr, unsigned int di_off, bool no_state)
|
||||||
{
|
{
|
||||||
h = std::max ((unsigned int) 16, h) * dpr + 0.5;
|
tl::PixelBuffer px = view->icon_for_layer (iter, w, h, dpr, di_off, no_state);
|
||||||
w = std::max ((unsigned int) 16, w) * dpr + 0.5;
|
QPixmap pixmap = QPixmap::fromImage (px.to_image ());
|
||||||
|
|
||||||
tl::color_t def_color = 0x808080;
|
|
||||||
tl::color_t fill_color = iter->has_fill_color (true) ? iter->eff_fill_color (true) : def_color;
|
|
||||||
tl::color_t frame_color = iter->has_frame_color (true) ? iter->eff_frame_color (true) : def_color;
|
|
||||||
|
|
||||||
tl::PixelBuffer image (w, h);
|
|
||||||
image.set_transparent (true);
|
|
||||||
image.fill (view->background_color ().rgb ());
|
|
||||||
|
|
||||||
// upper scanline is a dummy one
|
|
||||||
uint32_t *sl0 = (uint32_t *) image.scan_line (0);
|
|
||||||
uint32_t transparent = QColor (Qt::transparent).rgba ();
|
|
||||||
for (size_t i = 0; i < w; ++i) {
|
|
||||||
*sl0++ = transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: adjust the resolution according to the oversampling mode
|
|
||||||
lay::Bitmap fill (w, h, 1.0);
|
|
||||||
lay::Bitmap frame (w, h, 1.0);
|
|
||||||
lay::Bitmap text (w, h, 1.0);
|
|
||||||
lay::Bitmap vertex (w, h, 1.0);
|
|
||||||
|
|
||||||
unsigned int wp = w - 1;
|
|
||||||
|
|
||||||
if (! no_state && ! iter->visible (true)) {
|
|
||||||
|
|
||||||
wp = w / 4;
|
|
||||||
|
|
||||||
// Show the arrow if it is invisible also locally.
|
|
||||||
if (! iter->visible (false)) {
|
|
||||||
|
|
||||||
unsigned int aw = h / 4;
|
|
||||||
unsigned int ap = w / 2 - 1;
|
|
||||||
for (unsigned int i = 0; i <= aw; ++i) {
|
|
||||||
text.fill (h / 2 - 1 - i, ap, ap + aw - i + 1);
|
|
||||||
text.fill (h / 2 - 1 + i, ap, ap + aw - i + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! no_state && view->no_stipples ()) {
|
|
||||||
// Show a partial stipple pattern only for "no stipple" mode
|
|
||||||
for (unsigned int i = 1; i < h - 2; ++i) {
|
|
||||||
fill.fill (i, w - 1 - w / 4, w);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (unsigned int i = 1; i < h - 2; ++i) {
|
|
||||||
fill.fill (i, w - 1 - wp, w);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int lw = iter->width (true);
|
|
||||||
if (lw < 0) {
|
|
||||||
// default line width is 0 for parents and 1 for leafs
|
|
||||||
lw = iter->has_children () ? 0 : 1;
|
|
||||||
}
|
|
||||||
lw = lw * dpr + 0.5;
|
|
||||||
|
|
||||||
int p0 = lw / 2;
|
|
||||||
p0 = std::max (0, std::min (int (w / 4 - 1), p0));
|
|
||||||
|
|
||||||
int p1 = (lw - 1) / 2;
|
|
||||||
p1 = std::max (0, std::min (int (w / 4 - 1), p1));
|
|
||||||
|
|
||||||
int p0x = p0, p1x = p1;
|
|
||||||
unsigned int ddx = 0;
|
|
||||||
unsigned int ddy = h - 2 - p1 - p0;
|
|
||||||
if (iter->xfill (true)) {
|
|
||||||
ddx = wp - p0 - p1 - 1;
|
|
||||||
}
|
|
||||||
unsigned int d = ddx / 2;
|
|
||||||
|
|
||||||
frame.fill (p0, w - 1 - (wp - p1), w);
|
|
||||||
frame.fill (h - 2 - p1, w - 1 - (wp - p1), w);
|
|
||||||
|
|
||||||
for (unsigned int i = p0; i < h - 2; ++i) {
|
|
||||||
|
|
||||||
frame.fill (i, w - 1 - p0, w - p0);
|
|
||||||
frame.fill (i, w - 1 - (wp - p1), w - (wp - p1));
|
|
||||||
frame.fill (i, w - 1 - p0x, w - p0x);
|
|
||||||
frame.fill (i, w - 1 - (wp - p1x), w - (wp - p1x));
|
|
||||||
|
|
||||||
while (d < ddx) {
|
|
||||||
d += ddy;
|
|
||||||
frame.fill (i, w - 1 - p0x, w - p0x);
|
|
||||||
frame.fill (i, w - 1 - (wp - p1x), w - (wp - p1x));
|
|
||||||
++p0x;
|
|
||||||
++p1x;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (d >= ddx) {
|
|
||||||
d -= ddx;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! no_state && ! iter->valid (true)) {
|
|
||||||
|
|
||||||
unsigned int bp = w - 1 - ((w * 7) / 8 - 1);
|
|
||||||
unsigned int be = bp + h / 2;
|
|
||||||
unsigned int bw = h / 4 - 1;
|
|
||||||
unsigned int by = h / 2 - 1;
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < bw + 2; ++i) {
|
|
||||||
fill.clear (by - i, bp - 1, be);
|
|
||||||
fill.clear (by + i, bp - 1, be);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < bw; ++i) {
|
|
||||||
text.fill (by - i, bp + bw - i - 1, bp + bw - i + 1);
|
|
||||||
text.fill (by - i - 1, bp + bw - i - 1, bp + bw - i + 1);
|
|
||||||
text.fill (by - i, bp + bw + i, bp + bw + i + 2);
|
|
||||||
text.fill (by - i - 1, bp + bw + i, bp + bw + i + 2);
|
|
||||||
text.fill (by + i, bp + bw - i - 1, bp + bw - i + 1);
|
|
||||||
text.fill (by + i + 1, bp + bw - i - 1, bp + bw - i + 1);
|
|
||||||
text.fill (by + i, bp + bw + i, bp + bw + i + 2);
|
|
||||||
text.fill (by + i + 1, bp + bw + i, bp + bw + i + 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
vertex.fill (h / 2 - 1, w - 1 - wp / 2, w - wp / 2);
|
|
||||||
|
|
||||||
lay::ViewOp::Mode mode = lay::ViewOp::Copy;
|
|
||||||
|
|
||||||
// create fill
|
|
||||||
single_bitmap_to_image (lay::ViewOp (fill_color, mode, 0, iter->eff_dither_pattern (true), di_off), fill, &image, view->dither_pattern (), view->line_styles (), dpr, w, h);
|
|
||||||
// create frame
|
|
||||||
if (lw == 0) {
|
|
||||||
single_bitmap_to_image (lay::ViewOp (frame_color, mode, 0 /*solid line*/, 2 /*dotted*/, 0), frame, &image, view->dither_pattern (), view->line_styles (), dpr, w, h);
|
|
||||||
} else {
|
|
||||||
single_bitmap_to_image (lay::ViewOp (frame_color, mode, iter->eff_line_style (true), 0, 0, lay::ViewOp::Rect, lw), frame, &image, view->dither_pattern (), view->line_styles (), dpr, w, h);
|
|
||||||
}
|
|
||||||
// create text
|
|
||||||
single_bitmap_to_image (lay::ViewOp (frame_color, mode, 0, 0, 0), text, &image, view->dither_pattern (), view->line_styles (), dpr, w, h);
|
|
||||||
// create vertex
|
|
||||||
single_bitmap_to_image (lay::ViewOp (frame_color, mode, 0, 0, 0, lay::ViewOp::Cross, iter->marked (true) ? 9/*mark size*/ : 0), vertex, &image, view->dither_pattern (), view->line_styles (), dpr, w, h);
|
|
||||||
|
|
||||||
QPixmap pixmap = QPixmap::fromImage (image.to_image ());
|
|
||||||
#if QT_VERSION >= 0x050000
|
#if QT_VERSION >= 0x050000
|
||||||
pixmap.setDevicePixelRatio (dpr);
|
pixmap.setDevicePixelRatio (dpr);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -123,17 +123,17 @@ public:
|
||||||
QModelIndex index (lay::LayerPropertiesConstIterator iter, int column) const;
|
QModelIndex index (lay::LayerPropertiesConstIterator iter, int column) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Convert a QModelIndex to an iterator
|
* @brief Converts a QModelIndex to an iterator
|
||||||
*/
|
*/
|
||||||
lay::LayerPropertiesConstIterator iterator (const QModelIndex &index) const;
|
lay::LayerPropertiesConstIterator iterator (const QModelIndex &index) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get a flag indicating that an entry is hidden
|
* @brief Gets a flag indicating that an entry is hidden
|
||||||
*/
|
*/
|
||||||
bool is_hidden (const QModelIndex &index) const;
|
bool is_hidden (const QModelIndex &index) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the animation phase
|
* @brief Sets the animation phase
|
||||||
*/
|
*/
|
||||||
void set_phase (unsigned int ph);
|
void set_phase (unsigned int ph);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -731,6 +731,20 @@ LayoutView::update_menu (lay::LayoutView *view, lay::AbstractMenu &menu)
|
||||||
bool
|
bool
|
||||||
LayoutView::configure (const std::string &name, const std::string &value)
|
LayoutView::configure (const std::string &name, const std::string &value)
|
||||||
{
|
{
|
||||||
|
if (name == cfg_bitmap_oversampling) {
|
||||||
|
|
||||||
|
int os = 1;
|
||||||
|
tl::from_string (value, os);
|
||||||
|
mp_control_panel->set_oversampling (os);
|
||||||
|
|
||||||
|
} else if (name == cfg_highres_mode) {
|
||||||
|
|
||||||
|
bool hrm = false;
|
||||||
|
tl::from_string (value, hrm);
|
||||||
|
mp_control_panel->set_highres_mode (hrm);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (LayoutViewBase::configure (name, value)) {
|
if (LayoutViewBase::configure (name, value)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
namespace tl
|
namespace tl
|
||||||
{
|
{
|
||||||
|
|
@ -358,6 +359,141 @@ PixelBuffer::diff (const PixelBuffer &other) const
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PixelBuffer::blowup (tl::PixelBuffer &dest, unsigned int os)
|
||||||
|
{
|
||||||
|
tl_assert (dest.width () == width () * os);
|
||||||
|
tl_assert (dest.height () == height () * os);
|
||||||
|
|
||||||
|
unsigned int ymax = height ();
|
||||||
|
unsigned int xmax = width ();
|
||||||
|
|
||||||
|
for (unsigned int y = 0; y < ymax; ++y) {
|
||||||
|
for (unsigned int i = 0; i < os; ++i) {
|
||||||
|
const uint32_t *psrc = (const uint32_t *) scan_line (y);
|
||||||
|
uint32_t *pdest = (uint32_t *) dest.scan_line (y * os + i);
|
||||||
|
for (unsigned int x = 0; x < xmax; ++x) {
|
||||||
|
for (unsigned int j = 0; j < os; ++j) {
|
||||||
|
*pdest++ = *psrc;
|
||||||
|
}
|
||||||
|
++psrc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PixelBuffer::subsample (tl::PixelBuffer &dest, unsigned int os, double g)
|
||||||
|
{
|
||||||
|
// TODO: this is probably not compatible with the endianess of SPARC ..
|
||||||
|
|
||||||
|
// LUT's for combining the RGB channels
|
||||||
|
|
||||||
|
// forward transformation table
|
||||||
|
unsigned short lut1[256];
|
||||||
|
for (unsigned int i = 0; i < 256; ++i) {
|
||||||
|
double f = (65536 / (os * os)) - 1;
|
||||||
|
lut1[i] = (unsigned short)std::min (f, std::max (0.0, floor (0.5 + pow (i / 255.0, g) * f)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// backward transformation table
|
||||||
|
unsigned char lut2[65536];
|
||||||
|
for (unsigned int i = 0; i < 65536; ++i) {
|
||||||
|
double f = os * os * ((65536 / (os * os)) - 1);
|
||||||
|
lut2[i] = (unsigned char)std::min (255.0, std::max (0.0, floor (0.5 + pow (i / f, 1.0 / g) * 255.0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// LUT's for alpha channel
|
||||||
|
|
||||||
|
// forward transformation table
|
||||||
|
unsigned short luta1[256];
|
||||||
|
for (unsigned int i = 0; i < 256; ++i) {
|
||||||
|
double f = (65536 / (os * os)) - 1;
|
||||||
|
luta1[i] = (unsigned short)std::min (f, std::max (0.0, floor (0.5 + (i / 255.0) * f)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// backward transformation table
|
||||||
|
unsigned char luta2[65536];
|
||||||
|
for (unsigned int i = 0; i < 65536; ++i) {
|
||||||
|
double f = os * os * ((65536 / (os * os)) - 1);
|
||||||
|
luta2[i] = (unsigned char)std::min (255.0, std::max (0.0, floor (0.5 + (i / f) * 255.0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int ymax = dest.height ();
|
||||||
|
unsigned int xmax = dest.width ();
|
||||||
|
|
||||||
|
unsigned short *buffer = new unsigned short[xmax * 4];
|
||||||
|
|
||||||
|
for (unsigned int y = 0; y < ymax; ++y) {
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
const unsigned char *psrc = (const unsigned char *) scan_line (y * os);
|
||||||
|
unsigned short *pdest = buffer;
|
||||||
|
|
||||||
|
for (unsigned int x = 0; x < xmax; ++x) {
|
||||||
|
|
||||||
|
pdest[0] = lut1[psrc[0]];
|
||||||
|
pdest[1] = lut1[psrc[1]];
|
||||||
|
pdest[2] = lut1[psrc[2]];
|
||||||
|
pdest[3] = luta1[psrc[3]];
|
||||||
|
psrc += 4;
|
||||||
|
|
||||||
|
for (unsigned int j = os; j > 1; j--) {
|
||||||
|
pdest[0] += lut1[psrc[0]];
|
||||||
|
pdest[1] += lut1[psrc[1]];
|
||||||
|
pdest[2] += lut1[psrc[2]];
|
||||||
|
pdest[3] += luta1[psrc[3]];
|
||||||
|
psrc += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
pdest += 4;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 1; i < os; ++i) {
|
||||||
|
|
||||||
|
const unsigned char *psrc = (const unsigned char *) scan_line (y * os + i);
|
||||||
|
unsigned short *pdest = buffer;
|
||||||
|
|
||||||
|
for (unsigned int x = 0; x < xmax; ++x) {
|
||||||
|
|
||||||
|
for (unsigned int j = os; j > 0; j--) {
|
||||||
|
pdest[0] += lut1[psrc[0]];
|
||||||
|
pdest[1] += lut1[psrc[1]];
|
||||||
|
pdest[2] += lut1[psrc[2]];
|
||||||
|
pdest[3] += luta1[psrc[3]];
|
||||||
|
psrc += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
pdest += 4;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
unsigned char *pdest = (unsigned char *) dest.scan_line (y);
|
||||||
|
const unsigned short *psrc = buffer;
|
||||||
|
|
||||||
|
for (unsigned int x = 0; x < xmax; ++x) {
|
||||||
|
*pdest++ = lut2[*psrc++];
|
||||||
|
*pdest++ = lut2[*psrc++];
|
||||||
|
*pdest++ = lut2[*psrc++];
|
||||||
|
*pdest++ = luta2[*psrc++];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#if defined(HAVE_PNG)
|
#if defined(HAVE_PNG)
|
||||||
|
|
||||||
PixelBuffer
|
PixelBuffer
|
||||||
|
|
|
||||||
|
|
@ -257,6 +257,28 @@ public:
|
||||||
*/
|
*/
|
||||||
PixelBuffer diff (const PixelBuffer &other) const;
|
PixelBuffer diff (const PixelBuffer &other) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Subsamples the image and puts the subsampled image into the destination image
|
||||||
|
*
|
||||||
|
* @param dest Where the subsampled image goes to
|
||||||
|
* @param os The subsampling factor
|
||||||
|
* @param g The gamma value for color interpolation
|
||||||
|
*
|
||||||
|
* The dimension of the destination image must be set to the corresponding fraction of
|
||||||
|
* self's dimension.
|
||||||
|
*/
|
||||||
|
void subsample (tl::PixelBuffer &dest, unsigned int os, double g);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Scales the image into the given destination image
|
||||||
|
*
|
||||||
|
* @param dest Where the scaled image goes to
|
||||||
|
* @param os The scaling factor
|
||||||
|
*
|
||||||
|
* The destination images dimension must have been set of self's dimension times os.
|
||||||
|
*/
|
||||||
|
void blowup (tl::PixelBuffer &dest, unsigned int os);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the texts
|
* @brief Gets the texts
|
||||||
*
|
*
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue