NYPL Labs

Generative eBook Covers

header

Finding better covers for public domain ebooks

Here at NYPL Labs we’re working on an ebook-borrowing and reading app. On the technical side, Leonard Richardson is doing all the back end magic, consolidating multiple data sources for each book into a single concise format: title, author, book cover and description. John Nowak is writing the code of the app itself (that you will be able to download to your phone). I am doing the design (and writing blog posts). Many of the ebooks we will be offering come from public domain sites such as Project Gutenberg. If you spend a few minutes browsing that site you will notice that many of its ebooks either have a really crappy cover image or none at all:

PG cover PG cover PG cover

Book covers weren’t a big deal until the 20th century, but now they’re how people first interact with a book, so not having one really puts a book at a disadvantage. They are problematic, and not only in ebooks. It’s difficult to find high-quality, reusable covers of out-of-print or public domain books. There are some projects such as Recovering the Classics that approach this problem in interesting ways. However, we at NYPL are still left with very limited (and expensive) solutions to this problem.

Given that the app’s visual quality is highly dependant on ebook cover quality (a wall of bad book covers makes the whole app look bad) we had to have a solution for displaying ebooks with no cover or a bad cover. The easy answer in this situation is doing what retail websites do for products with no associated image: display a generic image.

iTunes no cover S&S no cover Abrams no cover

This is not a very elegant solution. When dealing with books, it seems lazy to have a “nothing to see here” image. We will have at least a title and an author to work with. The next obvious choice is to make a generic cover that incorporates the book’s title and author. This is also a common choice in software such as iBooks:

iBooks cover

Skeuomorphism aside, it is a decent book cover. However, it feels a bit cheesy and I wanted something more in line with the rest of the design of the app (a design which I am leaving for a future post). We need a design that can display very long titles (up to 80 characters) but that would also look good with short ones (two or three characters); it should allow for one credited author, multiple authors or none at all. I decided on a more plain and generic cover image:

NYPL cover 1

Needless to say this didn’t impress anyone; which is OK because the point was not to impress; we needed a cover that displayed author and title information and was legible to most people and this checked every box… but… at the same time… wouldn’t it be cool if

10 PRINT “BOOK COVER”

While discussing options for doing a better generative cover I remembered 10 PRINT, a generative-art project and book led by Casey Reas that explores one line of Commodore 64 (C64) code:

10 PRINT CHR$(205.5+RND(1)); : GOTO 10

This code draws one of two possible characters (diagonal up or diagonal down) on the screen at random, over and over again. The C64 screen can show up to 40 characters in a row. The end result is a maze-like graphic like the one seen in this video:

At the 2012 Eyeo festival, Casey Reas talked about this project, which involves nine other authors who are collected in this book. I highly recommend watching Reas’s presentation (link jumps to 30:11 when 10 PRINT is mentioned). The two characters–diagonal up and diagonal down–come from the C64 PETSCII character list which is laid out here on the Commodore keyboard:

PETSCII

Each key on the PETSCII keyboard has a geometric shape associated with it. These shapes can be used to generate primitive graphics in the C64 operating system. For example, here is a rounded rectangle (I added some space to make it easier to see each character):

5 3 3 3 9
2 0 0 0 2
2 0 0 0 2
a 3 3 3 b

In terms of the letters on the same keyboard, that rectangle looks like this:


UCCCI
B   B
B   B
JCCCK

10 PRINT was the starting point for my next ebook cover generator. In 10 PRINT a non-alphanumeric character is chosen by a random “coin toss” and displayed as a graphic. In my cover generator, a book’s title is transformed into a graphic. Each letter A-Z and digit 0-9 is replaced with its PETSCII graphic equivalent (e.g. the W gets replaced with an empty circle). I used Processing to quickly create sketches that allowed for some parameter control such as line thickness and grid size. For characters not on the PETSCII “keyboard” (such as accented Latin letters or Chinese characters) I chose a replacement graphic based on the output of passing the character into Processing’s int() function.

Colors and fonts

In order to have a variety of colors across the books, I decided to use the combined length of the book title and the author’s name as a seed number, and use that seed to generate a color. This color and its complementary are used for drawing the shapes. Processing has a few functions that let you easily create colors. I used the HSL color space which facilitates generating complementary colors (each color, or hue in HSL parlance, is located in a point on a circle, its complementary is the diametrically opposite point). The gist code:

int counts = title.length() + author.length();
// map the count to a number between 30 and 260
// (seemed to give the best results)
int colorSeed = int(map(counts, 2, 80, 30, 260));
// use HSL color space
colorMode(HSB, 360, 100, 100);
// main color is darker
shapeColor = color(colorSeed, baseSaturation, baseBrightness-(counts%20));
// complementary color
baseColor = color((colorSeed+180)%360, baseSaturation, baseBrightness); 

This results in something like:

hsl

To ensure legibility and avoid clashes with the generated colors, I always use black on white for text. I chose Avenir Next as the font. The app as a whole uses that font for its interface, it’s already installed on the OS and it contains glyphs for multiple languages.

There are more (and better) ways to create colors using code. I didn’t really go down the rabbit hole here but if you feel so inclined, take a look at Herman Tulleken’s work with procedural color palettes, Rob Simmon’s extensive work on color, or this cool post on emulating iTunes 11’s album cover color extractor.

Shapes

I created a function that draws graphic alternate characters for the letters A-Z and the digits 0-9. I decided to simplify a few graphics to more basic shapes: the PETSCII club (X) became three dots, and the spade (A) became a triangle.

I wrote a function that draws a shape given a character k, a position x,y and a size s. Here you can see the code for drawing the graphics for the letter Q (a filled circle) and the letter W (an open circle).

void drawShape(char k, int x, int y, int s) {
  ellipseMode(CORNER);
  fill(shapeColor);
  switch (k) {
    case 'q':
    case 'Q':
      ellipse(x, y, s, s);
      break;
    case 'w':
    case 'W':
      ellipse(x, y, s, s);
      s = s-(shapeThickness*2);
      fill(baseColor);
      ellipse(x+shapeThickness, y+shapeThickness, s, s);
      break;
    // plus all the other letters below
  }
}

My cover generator calls drawShape repeatedly for each character in a book’s title. The size of the shape is controlled by the length of the title: the longer the title, the smaller the shape.

Each letter in the title is replaced by a graphic and repeated as many times as it can fit in the space allotted. The resulting grid is a sort of visualization of the title; an alternate alphabet. In the example below, the M in “Macbeth” is replaced by a diagonal downwards stroke (the same character used to great effect in 10 PRINT). The A is replaced by a triangle (rather than the club found on the PETSCII keyboard). The C becomes a horizontal line offset from the top, the B a vertical line offset from the left, and so on. Since the title is short, the grid is large, and the full title is not visible, but you get the idea:

10 PRINT "BOOK COVER"

There is a Git repository for this cover generator you can play with.

Some more examples (notice how “Moby Dick”, nine characters including the space, does fit in the 3x3 grid below and how the M in “Max” is repeated):

Macbeth

MOB
Y D
ICK

Max

MA
XM

And so on:

Douglass Aesop

The original design featured the cover on a white (or very light) background. This proved problematic, as the text could be dissociated from the artwork, so we went for a more “enclosed” version (I especially like how the Ruzhen Li cover turned out!):

Doctorow Li Justice

We initially thought about generating all these images and putting them on a server along with the ebooks themselves, but 1) it is an inefficient use of network resources since we needed several different sizes and resolutions and 2) when converted to PNG the covers lose a lot of their quality. I ended up producing an Objective-C version of this code (Git repo) that will run on the device and generate a cover on-the-fly when no cover is available. The Obj-C version subclasses UIView and can be used as a fancy-ish “no cover found” replacement.

Cover, illustrated

Of course, these covers do not reflect the content of the book. You can’t get an idea of what the book is about by looking at the cover. However, Leonard brought up the fact that many Project Gutenberg books, such as this one, include illustrations embedded as JPG or PNG files. We decided to use those images, when they are available, as a starting point for a generated cover. Our idea is to generate one cover for each illustration in a book and let people decide which cover is best using a simple web interface.

I tried a very basic first pass using Python (which I later abandoned for Processing):

Sherlock

This lacks personality and becomes problematic as titles get longer. I then ran into Chris Marker and Jason Simon’s work, and was inspired:

Marker & Simon

I liked the desaturated color and emphasis on faces. Faces can be automatically detected in images using computer-vision algorithms, and some of those are included in OpenCV, an open-source library that can be used in Processing. Here’s my first attempt in the style of Marker and Simon, with and without face detection added:

no cv cv

I also tried variations on the design, adding or removing elements, and inverting the colors:

no cv line cv line no cv inverted

Since Leonard and I couldn’t agree on which variation was best, we decided to create a survey and let the people decide (I am not a fan of this approach, which can easily become a 41 shades of blue situation but I also didn’t have a compelling case for either version). The clear winner was, to my surprise, using inverted colors and no face detection:

flatland ten girls procopius

The final Processing sketch (Git repo) has many more parameters than the 10 PRINT generator:

Image Cover P5

Conclusion

As with many subjects, you can go really deep down the rabbit hole when it comes to creating the perfect automated book cover. What if we detect illustrations vs. photographs and produce a different style for each? What about detecting where the main image is so we can crop it better? What if we do some OCR on the images to automatically exclude text-heavy images which will probably not work as covers?

This can become a never-ending project and we have an app to ship. This is good enough for now. Of course, you are welcome to play with and improve on it:

Comments

Patron-generated content represents the views and interpretations of the patron, not necessarily those of The New York Public Library. For more information see NYPL's Website Terms and Conditions.

Can't judge books by these covers

Considering the history of book covers -- there's a chapter in Steven Heller's _Design Literacy_ -- the point is to make one book visually distinguishable from others, to capture a consumer's interest and sell books. Autogenerating book covers may thus be worse than serving no purpose - especially with titles in all caps - as they make it harder to distinguish each book. A simple, vertical list of mixed-case titles would be easier to use than rows and columns of near-identical rectangles. There's a reason why the Petite Planète books all looks similar - they're all in the same series, but use photo and color to show variation within the series. That's not an appropriate pattern to adopt when generating covers for unrelated books. Great idea, though, and an interesting read.

@Jonathan: I agree that

@Jonathan: I agree that nothing beats a professional, hand-made book cover. We want to get as close as we can. That said, one design has mixed case (10PRINT) the other has uppercase. Other reference points for this project were also Penguin Books: http://i.imgur.com/j41o33y.jpg and The Modern Library: http://i.imgur.com/Hh4MYD2.png (cannot paste links or images here).

What could be potentially

What could be potentially interesting is to vary some of the generator parameters based on specific meaningful things like genre, so that certain aspects of the book cover convey that information at a glance. If a given author or genre consistently had the same color palette (which is likely the most useful visual piece for finding something at a glance), it would keep their books visually consistent with each other and make them easy to identify relative to other authors/genres (I'm not sure which would be the more useful differentiator). It might even be possible (though harder to do in a useful manner) to figure out book themes (at a simplistic level, just do word counts and see which meaningful words show up the most) and have them impact as well. It's harder to figure out how to use that to generate something useful though.

Unfortunately we have very

Unfortunately we have very limited information for many books (besides title, some don't even have authors). We will definitely integrate some of these ideas if/when we get to have more data. One thing to remember is that these covers are for situations when the books have no cover at all (a badly designed cover is still considered a cover), and this usually only happens for obscure works whose metadata is limited.

Suggest varying the info block placement

The blocks line up and create a separate geometry of their own. Not only does it make your eye want to read the titles as if they are some kind of weird sentence but it makes it so that the imagery becomes sort of irrelevant, like they are just stuff in the space between info block rows. I'd try to figure out how to move it to different heights on the cover. Obviously, you'd have to figure out the consequences for the readability of the image itself but, if you can solve it, I think you'd improve an already extremely cool project. Good luck.

Generative Covers

You might want to have a look at Karsten Schmidt and Marian Bantjes' generative covers for Faber Finds, a pretty good collaboration between illustrator and digital artist. There's a good write-up of their process here: http://www.creativereview.co.uk/cr-blog/2008/july/faber-finds-generative-book-covers

Avoiding uniformity

Sure, but as this blog post shows, there are *huge* opportunities for differentiation between books: simply encoding the genre and the year of publication into parameters for the algorithm would be a great improvement. It will result in a library in which books in different "ages" are styled differently (just as in real life) and genres can have some manual tuning applied to make the covers reflect some aspect we usually associated with them. E.g. different eras in history could be represented with different colour schemes; fine poetry could have "calming" and non-busy designs, philosophical pieces could have the more abstract covers such as your first ones (used on the Macbeth example), history books could have the washed-out "retro" look of your last covers (used on "Ten American Girls from History"), etc.

Unfortunately we do not have

Unfortunately we do not have genre nor year for many books. Leonard Richardson (@leonardr) has been doing a lot of algorithmic cleanup of this dataset and every day obtains new information from each work. Maybe one day we incorporate the newly found data into the cover. The first, geometric, algorithm is supposed to be somewhat of a fancy placeholder image and not much else: basically the image that would appear in your device when you drag-drop some random ePub that has no cover; it will probably have a title and maybe an author. The second one goes a bit further, making use of images inside the book.

Crowdsource it.

Crowdsource it. Or better yet, use this method to generate the initial covers, but one, have a human veto which design to use (I assume each book will have generated a few), then have the community which you'll inevitably build help out with design. Have people help with design and others vote for their favorite ones. There's a book community website (not goodreads) that rewards members when they add more information about the books. Character names, locations, book covers, pictures etc. Also ... these are digital formats, why settle for only one cover?

Correct. That's what will

Correct. That's what will happen for the illustrated covers. Some books have hundreds of illustrations! We're going to show all generated covers to people who will vote to decide which works best.

Numbers involved?

How many books will you be generating covers for initially? What % of them have an image to pull? For those with no image.... 1. Did you consider just using the author's name as the seed, so all the works from a single author would have the same color palette? 2. Did you consider taking a word from the title/summary of a given book and then pulling CreativeCommons images matching that word?

There are 45k Gutenberg books

There are 45k Gutenberg books but we plan on including pretty my every public domain ebook under the sun (numbers increase quickly). ~50% of Gutenberg books have an illustration. Using author as seed is a good idea. We did go the creative commons images/illustrations route but abandoned it (no screenshots for that unfortunately).

s/complimentary/complementary

Every time I read the phrase "complimentary colors", it's like a dagger in my heart. These are colors that complement each other, that go together well, not colors that say nice things to each other!

Thanks for the typo discovery

Thanks for the typo discovery. Fixed! Blame it on my ESL.

It is easier to use a

It is easier to use a talented artist and pay them to generate the cover. This way you are sure to get an orginal cover that doesn't smell like poo.

Yes. And costs scale up

Yes. And costs scale up really fast when the need is to generate tens of thousands of covers. A decent cover can be in the hundreds of dollars.

I suggest you increase the

I suggest you increase the margins where your text is placed. It'll make the design more elegant. Here's an article all about this: https://medium.com/message/lets-talk-about-margins-14646574c385

Will look into it. Thank you.

Will look into it. Thank you.

Book Design Covers

Hi, I think you should open this up as a project for teachers to embed into their lessons. Let the children of NYC work on designing book covers for these literary classics or open it up to the world for a global perspective. It's bound to make for an interesting year - for both you and students. When I was a senior in my Graphics Art class we were asked to design book covers. I designed a graphic version of Alice in Wonderland. I still remember the project to this day...and it's been almost 30 years. B

Love what you're doing - have

Love what you're doing - have you considered using crowdsourcing services like PickFu or CrowdFlower to help pick the best book covers?

Another Use Case

It seems to me that there is a third use case here, intermediate between the hand-crafted scenario and the Gutenberg scenario. I produce a medium number of eBooks, measured in tens rather than in thousands, but I have no budget to pay an artist to hand-craft covers. I am finding imagecoverp5print a useful tool to generate decent-looking covers much faster and more easily than I've been able to do in the past. I have tweaked the code to better support this use case, so that I can interactively override the hue, more easily select fonts and font sizes, suppress the greyscale, and so forth. I'm pretty happy with the result.

That's great! I was worried

That's great! I was worried that the code might not be flexible enough. I am glad you found it useful. Let me know if you have any questions about it.

A Cool Synesthetic Refinement

I recently implemented a small change to the system. Now instead of selecting the hue for the cover at random or manually, it is computed from the Dewey Decimal Number of the subject. Now I can see at a glance what a document is about (red for language, blue for technology, green for literature, etc.) and my books form a nice rainbow on my virtual bookshelf!

That's awesome. We left the

That's awesome. We left the color part connected to the author/title of the book because the books that make use of the cover generator are usually those for which we have little to no other information. We could add something like this for situations when there is some extra metadata in the book.

calibre port?

Any intention to port this as a plugin for calibre (which has a not as pretty cover generation plugin shipped with it)? If not, any opposition to a potential port of the styles/logic in this post to calibre by someone else?

I am unfamiliar with Calibre

I am unfamiliar with Calibre and currently there are no plans to port this code to it but anyone is free to port or use whatever they want from this idea in any other project.

Processing 3

Are there any plans to upgrade this code to Processing 3? Or any suggestions for doing it? The code itself isn't hard to revise but the libraries like controlP5 look more problematic.

One thing you could do is, if

One thing you could do is, if you are already satisfied with certain parameters, write them down and remove ControlP5 entirely. Then hard-code the parameters to the variables that CP5 is altering. I want to update the code to Processing 3 but it will take me a while.

Processing 3 Suggestion

Thanks. That makes sense. But I suspect what I'll do is just keep using Processing 2 for my project until you get your code updated.

I'd also try normalising the

I'd also try normalising the book titles using something like Soundex encoding, to remove small variations due to spelling or small title differences across different editions.