From 048cb9327965b78afba4f93f9345b043b3929bfa Mon Sep 17 00:00:00 2001 From: kiirala Date: Sun, 14 Dec 2008 19:22:09 +0000 Subject: [PATCH] Filter quality setting revised, seems to not crash when viewing filters.svg --- src/display/nr-arena-item.cpp | 4 +- src/display/nr-filter.cpp | 155 +++++++++++++++++++++++++--------- src/display/nr-filter.h | 7 +- 3 files changed, 121 insertions(+), 45 deletions(-) diff --git a/src/display/nr-arena-item.cpp b/src/display/nr-arena-item.cpp index b4fada749..8e66e13be 100644 --- a/src/display/nr-arena-item.cpp +++ b/src/display/nr-arena-item.cpp @@ -323,7 +323,7 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area if (nr_rect_l_test_empty(carea)) return item->state | NR_ARENA_ITEM_STATE_RENDER; if (item->filter && filter) { - item->filter->area_enlarge (carea, item->ctm); + item->filter->area_enlarge (carea, item); nr_rect_l_intersect (&carea, &carea, &item->bbox); } @@ -426,7 +426,7 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area ipb.visible_area = pb->visible_area; if (item->filter && filter) { - item->filter->area_enlarge (ipb.visible_area, item->ctm); + item->filter->area_enlarge (ipb.visible_area, item); } unsigned int state = NR_ARENA_ITEM_VIRTUAL (item, render) (ct, item, &carea, &ipb, flags); diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp index 01a092177..2f437ba6c 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -6,7 +6,7 @@ * Author: * Niko Kiirala * - * Copyright (C) 2006,2007 Niko Kiirala + * Copyright (C) 2006-2008 Niko Kiirala * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -44,6 +44,7 @@ #include "libnr/nr-blit.h" #include "libnr/nr-matrix.h" #include "libnr/nr-scale.h" +#include "2geom/rect.h" #include "svg/svg-length.h" #include "sp-filter-units.h" #include "preferences.h" @@ -55,6 +56,24 @@ using Inkscape::round; namespace NR { +static Geom::OptRect get_item_bbox(NRArenaItem const *item) { + Geom::Rect item_bbox; + if (item->item_bbox) { + item_bbox = *(item->item_bbox); + } else { + // Bounding box might not exist, so create a dummy one. + Geom::Point zero(0, 0); + item_bbox = Geom::Rect(zero, zero); + } + if (item_bbox.min()[X] > item_bbox.max()[X] + || item_bbox.min()[Y] > item_bbox.max()[Y]) + { + // In case of negative-size bbox, return an empty OptRect + return Geom::OptRect(); + } + return Geom::OptRect(item_bbox); +} + Filter::Filter() { _primitive_count = 0; @@ -121,18 +140,13 @@ int Filter::render(NRArenaItem const *item, NRPixBlock *pb) slot.set_quality(filterquality); Geom::Rect item_bbox; - if (item->item_bbox) { - item_bbox = *(item->item_bbox); - } else { - // Bounding box might not exist, so create a dummy one. - Geom::Point zero(0, 0); - item_bbox = Geom::Rect(zero, zero); - } - if (item_bbox.min()[X] > item_bbox.max()[X] - || item_bbox.min()[Y] > item_bbox.max()[Y]) { - // Code below assumes non-negative size. - return 1; + Geom::OptRect maybe_bbox = get_item_bbox(item); + if (maybe_bbox.isEmpty()) { + // Code below needs a bounding box + return 1; + } + item_bbox = *maybe_bbox; } Geom::Rect filter_area = filter_effect_area(item_bbox); @@ -147,30 +161,14 @@ int Filter::render(NRArenaItem const *item, NRPixBlock *pb) units.set_filter_area(from_2geom(filter_area)); // TODO: with filterRes of 0x0 should return an empty image + std::pair resolution + = _filter_resolution(filter_area, trans, filterquality); + units.set_resolution(resolution.first, resolution.second); if (_x_pixels > 0) { - double y_len; - if (_y_pixels > 0) { - y_len = _y_pixels; - } else { - y_len = (_x_pixels * (filter_area.max()[Y] - filter_area.min()[Y])) - / (filter_area.max()[X] - filter_area.min()[X]); - } units.set_automatic_resolution(false); - units.set_resolution(_x_pixels, y_len); - } else { - Geom::Point origo = filter_area.min(); - origo *= trans; - Geom::Point max_i(filter_area.max()[X], filter_area.min()[Y]); - max_i *= trans; - Geom::Point max_j(filter_area.min()[X], filter_area.max()[Y]); - max_j *= trans; - double i_len = sqrt((origo[X] - max_i[X]) * (origo[X] - max_i[X]) - + (origo[Y] - max_i[Y]) * (origo[Y] - max_i[Y])); - double j_len = sqrt((origo[X] - max_j[X]) * (origo[X] - max_j[X]) - + (origo[Y] - max_j[Y]) * (origo[Y] - max_j[Y])); + } + else { units.set_automatic_resolution(true); - double const divisor = _resolution_divisor(filterquality); - units.set_resolution(i_len / divisor, j_len / divisor); } units.set_paraller(false); @@ -218,10 +216,41 @@ int Filter::render(NRArenaItem const *item, NRPixBlock *pb) return 0; } -void Filter::area_enlarge(NRRectL &bbox, Geom::Matrix const &m) { +void Filter::area_enlarge(NRRectL &bbox, NRArenaItem const *item) const { for (int i = 0 ; i < _primitive_count ; i++) { - if (_primitive[i]) _primitive[i]->area_enlarge(bbox, m); + if (_primitive[i]) _primitive[i]->area_enlarge(bbox, item->ctm); } +/* + TODO: something. See images at the bottom of filters.svg with medium-low + filtering quality. + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + FilterQuality const filterquality = (FilterQuality)prefs->getInt("/options/filterquality/value"); + + if (_x_pixels <= 0 && (filterquality == FILTER_QUALITY_BEST || + filterquality == FILTER_QUALITY_BETTER)) { + return; + } + + Geom::Rect item_bbox; + Geom::OptRect maybe_bbox = get_item_bbox(item); + if (maybe_bbox.isEmpty()) { + // Code below needs a bounding box + return; + } + item_bbox = *maybe_bbox; + + std::pair res_low + = _filter_resolution(item_bbox, item->ctm, filterquality); + //std::pair res_full + // = _filter_resolution(item_bbox, item->ctm, FILTER_QUALITY_BEST); + double pixels_per_block = fmax(item_bbox.width() / res_low.first, + item_bbox.height() / res_low.second); + bbox.x0 -= (int)pixels_per_block; + bbox.x1 += (int)pixels_per_block; + bbox.y0 -= (int)pixels_per_block; + bbox.y1 += (int)pixels_per_block; +*/ } void Filter::bbox_enlarge(NRRectL &bbox) { @@ -439,24 +468,68 @@ void Filter::reset_resolution() { _y_pixels = -1; } -double Filter::_resolution_divisor(FilterQuality const quality) const { - double divisor = 1; +int Filter::_resolution_limit(FilterQuality const quality) const { + int limit = -1; switch (quality) { case FILTER_QUALITY_WORST: - divisor = 8; + limit = 32; break; case FILTER_QUALITY_WORSE: - divisor = 4; + limit = 64; break; case FILTER_QUALITY_NORMAL: - divisor = 2; + limit = 256; break; case FILTER_QUALITY_BETTER: case FILTER_QUALITY_BEST: default: break; } - return divisor; + return limit; +} + +std::pair Filter::_filter_resolution( + Geom::Rect const &area, Geom::Matrix const &trans, + FilterQuality const filterquality) const +{ + std::pair resolution; + if (_x_pixels > 0) { + double y_len; + if (_y_pixels > 0) { + y_len = _y_pixels; + } else { + y_len = (_x_pixels * (area.max()[Y] - area.min()[Y])) + / (area.max()[X] - area.min()[X]); + } + resolution.first = _x_pixels; + resolution.second = y_len; + } else { + Geom::Point origo = area.min(); + origo *= trans; + Geom::Point max_i(area.max()[X], area.min()[Y]); + max_i *= trans; + Geom::Point max_j(area.min()[X], area.max()[Y]); + max_j *= trans; + double i_len = sqrt((origo[X] - max_i[X]) * (origo[X] - max_i[X]) + + (origo[Y] - max_i[Y]) * (origo[Y] - max_i[Y])); + double j_len = sqrt((origo[X] - max_j[X]) * (origo[X] - max_j[X]) + + (origo[Y] - max_j[Y]) * (origo[Y] - max_j[Y])); + int limit = _resolution_limit(filterquality); + if (limit > 0 && (i_len > limit || j_len > limit)) { + double aspect_ratio = i_len / j_len; + if (i_len > j_len) { + i_len = limit; + j_len = i_len / aspect_ratio; + } + else { + j_len = limit; + i_len = j_len * aspect_ratio; + } + } + resolution.first = i_len; + resolution.second = j_len; + } + return resolution; } } /* namespace NR */ diff --git a/src/display/nr-filter.h b/src/display/nr-filter.h index ae3857c65..b00cbf7d7 100644 --- a/src/display/nr-filter.h +++ b/src/display/nr-filter.h @@ -144,7 +144,7 @@ public: * to be rendered so that after filtering, the original area is * drawn correctly. */ - void area_enlarge(NRRectL &area, Geom::Matrix const &m); + void area_enlarge(NRRectL &area, NRArenaItem const *item) const; /** * Given an object bounding box, this function enlarges it so that * it contains the filter effect area. @@ -198,7 +198,10 @@ private: void _create_constructor_table(); void _enlarge_primitive_table(); void _common_init(); - double _resolution_divisor(FilterQuality const quality) const; + int _resolution_limit(FilterQuality const quality) const; + std::pair _filter_resolution(Geom::Rect const &area, + Geom::Matrix const &trans, + FilterQuality const q) const; }; -- 2.30.2