Border-Radius-Style Table Cell Corners in iText

Recently, I researched and implemented the iText PDF library for Java in order to automatically generate some pretty PDFs. I ran into an issue, however, when I realized that cells can only be given rounded corners through packaged routines via the PdfContentByte.roundRectangle() method, which only allows for all corners to be rounded at once. This was going to be a problem, since I only needed certain corners to be rounded on certain cells. Here is the solution I came up with:

/**
 * Cell event class for applying rounded corners and gradient backgrounds to
 * table cells.
 */
public class PdfRoundCorners implements PdfPCellEvent {

    private BaseColor[] colorFill;
    private boolean topLeft;
    private boolean topRight;
    private boolean bottomRight;
    private boolean bottomLeft;

    /**
     * Create a new PdfRoundCorners event while specifying a single fill color
     * and which corners will be rounded.
     *
     * @param colorFill The BaseColor to use as the fill color.
     * @param topLeft If true, top left corner will be rounded.
     * @param topRight If true, top right corner will be rounded.
     * @param bottomRight If true, bottom right corner will be rounded.
     * @param bottomLeft If true, bottom left corner will be rounded.
     */
    public PdfRoundCorners(
            BaseColor colorFill,
            boolean topLeft,
            boolean topRight,
            boolean bottomRight,
            boolean bottomLeft) {
        this.colorFill = new BaseColor[]{colorFill};
        this.topLeft = topLeft;
        this.topRight = topRight;
        this.bottomRight = bottomRight;
        this.bottomLeft = bottomLeft;
    }

    /**
     * Create a new PdfRoundCorners event while specifying a vertical background
     * gradient and which corners will be rounded.
     *
     * @param colorFill An array of two BaseColors which will be used to create
     * the gradient.
     * @param topLeft If true, top left corner will be rounded.
     * @param topRight If true, top right corner will be rounded.
     * @param bottomRight If true, bottom right corner will be rounded.
     * @param bottomLeft If true, bottom left corner will be rounded.
     */
    public PdfRoundCorners(
            BaseColor[] colorFill,
            boolean topLeft,
            boolean topRight,
            boolean bottomRight,
            boolean bottomLeft) {
        this.colorFill = colorFill;
        this.topLeft = topLeft;
        this.topRight = topRight;
        this.bottomRight = bottomRight;
        this.bottomLeft = bottomLeft;
    }

    /**
     * Interface method for drawing the background fill pattern.
     */
    @Override
    public void cellLayout(PdfPCell cell, Rectangle rect, PdfContentByte[] canvas) {
        // Get the cell's background canvas.
        PdfContentByte cb = canvas[PdfPTable.BACKGROUNDCANVAS];

        // Adjust left and right positions to fix visible gaps.
        float left = rect.getLeft() - (PdfStyle.CELL_BORDER_WIDTH / 2);
        float top = rect.getTop();
        float right = rect.getRight() + (PdfStyle.CELL_BORDER_WIDTH / 2);
        float bottom = rect.getBottom();

        // Set the fill color or gradient.
        if(colorFill.length < 2) {
            cb.setColorFill(colorFill[0]);
        } else {
            PdfShading shading = PdfShading.simpleAxial(
                    cb.getPdfWriter(), left, top, left, bottom, colorFill[0], colorFill[1]);
            PdfShadingPattern shadingPattern = new PdfShadingPattern(shading);
            cb.setShadingFill(shadingPattern);
        }

        // Define the background box including rounded corners.
        if(topLeft) {
            cb.moveTo(left, top - PdfStyle.CELL_CORNER_RADIUS);
            cb.curveTo(left, top, left + PdfStyle.CELL_CORNER_RADIUS, top);
        } else cb.moveTo(left, top);

        if(topRight) {
            cb.lineTo(right - PdfStyle.CELL_CORNER_RADIUS, top);
            cb.curveTo(right, top, right, top - PdfStyle.CELL_CORNER_RADIUS);
        } else cb.lineTo(right, top);

        if(bottomRight) {
            cb.lineTo(right, bottom + PdfStyle.CELL_CORNER_RADIUS);
            cb.curveTo(right, bottom, right - PdfStyle.CELL_CORNER_RADIUS, bottom);
        } else cb.lineTo(right, bottom);

        if(bottomLeft) {
            cb.lineTo(left + PdfStyle.CELL_CORNER_RADIUS, bottom);
            cb.curveTo(left, bottom, left, bottom + PdfStyle.CELL_CORNER_RADIUS);
        } else cb.lineTo(left, bottom);

        if(topLeft) cb.lineTo(left, top - PdfStyle.CELL_CORNER_RADIUS);
        else cb.lineTo(left, top);

        cb.closePath();

        // Fill it up!
        cb.fill();
    }

}

I literally had to trace out a rounded rectangle using a stroke path. What's special about this event class is that you can specify either a single fill color, or two colors to represent a gradient. You can also mark specifically which corners should be rounded. Of course it goes without saying, but it's all vector based. So no scaling issues! Here's an example of how it looks:

I couldn't find anything else like this out there, so I hope someone else can get some use out of it!

Posted in Java | Tagged , , , , , | 4 Comments

Find PDF Size with Ruby and XPDF

Here’s a fun little script I wrote today to find the width and height in points of a PDF file using Ruby and XPDF. It prints the width and height out on their own lines respectively so the output can be easily digested by other programs:

#!/usr/bin/ruby

# Print usage.
if ARGV.count < 1
  puts "Usage: getpdfsize path_to_pdf"
  exit
end

# Get the page size line from pdfinfo using
# backticks to execute a shell command.
output = `pdfinfo #{ARGV[0]} | grep "Page size:"`

# Extract the size values.
size = output.match /([\d]+) x ([\d]+)/

# Print them each out on their own line.
puts size[1], size[2]
Posted in Miscellaneous | Tagged , , , | Leave a comment

jQuery.live() Craziness

Here’s an interesting issue that came up recently. The other day, I managed to tackle a large bug at work that led to a tremendous speed increase in our app. This bug had been around for a while, but its cause hadn’t yet been determined.

It turns out that the culprit was the $.live() trigger type in the jQuery library. Let it be known that $.live() generally does not behave as expected, particularly when it is called on a jQuery selector that includes a context. We had been using the following method for calling $.live():

$("input[title='Update']", "#module_a").live("click", function () {
    // Event handling code...
});

The above code does not function the way you’d think. First of all, when specifying a context for a live event trigger (as “#module_a” was specified above), that context must exist already in the document. This goes against what you’d expect from an event trigger that is set up in this way. After all, live triggers are distinguished from simple bind triggers in that they are supposed to apply not just to existing elements but to future ones as well. Second, a context must be specified as a DOM element and nothing else. So that code should have been written this way:

// The only difference here is that "#module_a" is
// now $("#module_a")[0] which gets the DOM
// element of #module_a.
$("input[title='Update']", $("#module_a")[0]).live("click", function () {
    // Event handling code...
});

Our problem was two-fold. We had not yet created the context for that trigger. Furthermore, we were not specifying the context correctly. We naturally assumed that contexts specified for live triggers work as they do in any other case, accepting either a selector string, jQuery object, or DOM element.

The net effect of this was that large amounts of live trigger listeners were being installed on the document root, the default context for live triggers. So any event that fired in our app had to make it through a “gauntlet” of bubble listeners. We saw profile figures showing thousands of calls to matchSelector drop to tens of calls once we fixed this.

The jQuery documentation for live (here) does mention this special behavior under the “Event Context” section, but it is not given nearly enough emphasis considering the impact it can have on performance in large web applications. In fact, I found out about the issue on an entirely separate site: NetTuts+. I hope they work out this quirky behavior in a future release.

Posted in Javascript/CSS, Miscellaneous | Tagged , , , , | Leave a comment

I <3 Ruby

I have recently taken up the task of learning the Ruby language. After much endorsement from colleagues, I decided it was worth checking out. Well, as it turns out, it was! There is a lot to like about this language. It seems the entire design was guided by the idea that programming can be more simple, intuitive, and fun. The creator of the language, Yukihiro Matsumoto, has successfully accounted for many of the common problems encountered in programming. Ruby has also gained widespread popularity, which is something that many well-meaning languages do not manage to do. I would encourage anyone else to give it a swing.

Here are the two resources I have found most useful thus far:
tryruby.org and www.rubykoans.com

The first of those two is a really basic walkthrough of some of the essential functionality. The second is a brilliantly conceived and more comprehensive tour of the language a la Zen poetry. It is called “Ruby Koans” and it’s a really great way to begin learning Ruby. I just finished the whole course and I wanted to post a snippet from the last project.

The following is the “Proxy” class, which you must design in the “Proxy Object Project”:

# A proxy class which can act as a buffer to other classes
# to add functionality.
class Proxy

  # Automatically creates getter method for property "messages".
  attr_reader :messages

  # Constructor for the class.
  def initialize(target_object)

    # Captures the object to be proxied.
    @object = target_object

    # Used to store which methods have been called.
    # Set to empty array.
    @messages = []

    # Used to store tally of method calls per method name.
    # Set to empty Hash with default value of 0.
    @method_calls = Hash.new(0)
  end

  # Automatically called when a method is called for the Proxy class
  # that does not exist.
  def method_missing(method_name, *args, &block)

    # The method name is appended to the messages array.
    @messages << method_name

    # The number of calls for that method is incremented by 1.
    @method_calls[method_name] += 1

    # Uses the send method to forward the method call to
    # the object that is proxied.
    @object.send(method_name, *args, &block)
  end

  # Determines if a method has been called previously.
  def called?(method_name)

    # Is the method name included in the messages array?
    @messages.include?(method_name)
  end

  # Returns the number of times a method was called.
  def number_of_times_called(method_name)

    # How many calls were tallied for that method?
    @method_calls[method_name]
  end
end

Though the snippet has been commented to death, there are still things which might not make sense to someone not familiar with Ruby. I would only suggest that anyone who’s interested investigate further. It’s great how much can be done with so little code!

Posted in Coding | Tagged , , , , | Leave a comment

Animated, Prettified Search Bar

Hello, everyone! I recently modified the search bar to look and act more respectable. These days, you ain’t nothin’ if you don’t got a nice lookin’, mac-style search bar. I got the idea to animate the search bar in this way from an excellent web-design blog called Web Designer Wall, which some of you might be familiar with. The idea was theirs, but the code is original. As you’ll see, it wasn’t that hard to cook up!

Here is the css that was involved:

#s {
	border: 0px;

	background: url('http://www.charlesdavidsanders.com/search.png') no-repeat 3px center #fff;
	padding: 0px 0px 0px 20px;

	border-radius: 10px;
	-webkit-border-radius: 10px;
	-moz-border-radius: 10px;

	box-shadow: inset 0px 0px 1px black;
	-webkit-box-shadow: inset 0px 0px 1px black;
	-moz-box-shadow: inset 0px 0px 1px black;

	height: 20px;
	width: 100px;
}

The background url is just a little 17×17 search icon that can be easily acquired anywhere or made using something as simple as MS Paint. You can see that it is set not to repeat with a horizontal offset of 3px to the right and a centered vertical alignment. The padding is only on the left and is meant to prevent the search text from overlapping the search icon. The border radius is adjusted to make the sides round and the box shadow is inset to give the search field a softer appearance.

Here is the Javascript, which uses jQuery, that was used to animate the bar:

$("#s").focus(function () {
	$(this).animate({ width: '150px' }, 300);
});

$("#s").blur(function () {
	$(this).animate({ width: '100px' }, 300);
});

JQuery is used to select the input that has “s” as an id. Then, the focus and blur events are given trigger functions that animate the input. It’s pretty simple stuff as you can see. The animate function of the jQuery library takes several arguments, but the simplest configuration is seen here. The first argument is a Javascript object that contains all the css properties to be animated. The second is the duration of the animation in milliseconds. I hope others will get some use out of these simple and effective tricks!

Posted in Javascript/CSS | Tagged , , , , | Leave a comment

Web 2.0-ification

Hello, everyone! I am continuing to adjust the look of the page. You may have noticed that the navigation bar got snazified. I also added a Code section which features a bit of sample code and a link to a demo project. The demo project requires a username and password. If you’re interested in checking it out, just drop a comment on that page and I’ll give you access. Cheers!

Posted in Javascript/CSS | Tagged , , , | Leave a comment

New Content

I recently spent some time adding the new sections visible in the navigation bar. Information about the background image is now available as well as general biographical information. My resume is viewable in prettified format and you can also find me on LinkedIn from that section as well.

Posted in Miscellaneous | Tagged , , | Leave a comment

Greetings!

Hey, folks! Welcome to the personal homepage of musician and website designer David Sanders. I will be adding content to the site soon, including music samples and code project demos. Keep dropping by to see what’s next!

Posted in Miscellaneous | Leave a comment