Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Google Summer of Code 2021 with Open Printing (The Linux Foundation)

Warm Greetings to everyone reading this post. Finally the very exciting coding period of the Google Summer of Code 2021, is coming to an end. In this blog, I am going to talk about all the work that I did during my Google Summer of Code and some details about my GSoC project.

Project details

Title : Create a universal filter to replace the chain of individual cups filters.

Description : CUPS uses various filters to convert one file type to another to facilitate printing in linux. These filters have existed as external binary executables from a long time. Later it was decided to convert these filters into filter functions, as calling external executables is a resource consuming process. Most of the filters had already been converted to filter functions, and the remaining functions were to be converted in this year's GSoC by another student. Now that filters are converted to filter functions, there was a need to create a single utility, which would call these filter functions according to the requirement, and that exactly was what my project was all about. I created a "universal" filter function, which would be called once, and would in turn create the required filter chain, and call it to perform the conversion.

Implementation details

In this section, I will talk about the different files that I created, and for what will they be used


This file gets compiled to form the main universal binary file, which interacts with the user. The call scheme of this filter is exactly the same as the call scheme of other filters that cups uses. The following tasks are done inside this file

  1. It reads the environment variables CONTENT_TYPE and FINAL_CONTENT_TYPE and determines what the input and output types are.
  2. Then it stuffs the input and output types into a struct variable of type filter_input_output_format_t
  3. Finally, it calls the filterCUPSWrapper utility with the command line arguments and the struct variable created above.
  4. Lastly, it handles the output sent by the wrapper utility, and logs the results.


This is the main file inside which the logic of the universal filter resides. To give you an overview, in this file, we accept the input and output types as arguments, and depending on those, we determine what all filters to add in the filter chain. Once the filter chain is created, it calls the filterChain utility inside the filter.h file which in turn executes the filters in the filter chain one by one, using filter functions. We then handle the output returned by filterChain and pass on the received output to the stub file after logging some stuff.

How is the filter chain created?

The generation of the filter chain is based largely on the pdf printing workflow including some exceptions. The pdf printing workflow basically means that any input type is first convert into pdf using the appropriate filter, and then pdf would be converted to the required type. For example, to convert image/jpeg to application/postscript, the filters added to the chain are imagetopdf pdftopdf pdftops


There are certain exceptions in the pdf printing workflow. Some of them are :

  1. If input type is an image, and the output is raster : Then, instead of going the pdf way, we directly using imagetoraster functions.
  2. If the input type is adobe-reader-postscript, then instead of converting it to pdf, we first convert it into raster(if output type if raster, we stop here), or if further conversions are required, we convert rastertopdf, and then pdfto.... (whatever the output type is)


CUPS uses .convs files to determine what all filters to use when converting from one type to another. These .convs files contain conversion rules according to which the filter path is determined.

To integrate my universal filter with cups (and to make the cups' cupsfilter utility, use my filters, this universal.convs file was required. It contains all the input types and the output types, and also an interim type application/vnd.universal-input


This file was only created to make CUPS recognize the application/vnd.universal-input as a file type.

I also created this shell script, which would help my to test the universal function easily. Currently this file has not been pushed to any of the branches, but if need arises, I will add it to the cups-filters repository.

Minor changes in other files

There were some other changes required in other files like the , or the .gitignore file, so as to ensure that the code of the universal function compiles properly when the code of cups-filters is compiled.

My experience with GSoC and Open Printing

I had a really nice experience working with Open Printing for GSoC 2021. My mentors were very supportive, and very quick to help whenever I faced a problem. The entire GSoC Program was a very great learning experience for me, and I really felt empowered getting to create a part of a program that is going to be used by a lot of users in the future.


Currently all the code that I have written resides in the universal branch of my fork of the cups-filters upstream code. The code could be accessed from here The code in this branch has been merged from time to time with the code from the master branch of the upstream repo, (so as to add support for the new filters which get converted to filter functions)

Here are some commits with major code additions :

  1. f6043f : Project initialisation (Made changes in makefile to compile the universal function, and wrote basic structure of universal function)

  2. 55bb6f : Wrote basic logic (as comments) for deciding the orders of filters in the filter chain

  3. c5e6e : Wrote code for generating the filter chain, checking the chain, and calling the filterChain function

  4. b632f0 : Made changes to incorporate urf and pwg as input types

  5. 075380 : Added support for adobe-reader-postscript type. Also added support for more input types (image/x... and application/x-...)

As of now, most of project is almost complete, and the code with be merged in the upstream repo after consulting with the mentors.

Post GSoC

One important thing that I will continue to do is to provide support for the universal filter function which I have created, and will keep working on improvements which could be added in the filter. Other than that, I will also try to take some time out of my academics and keep on contributing to the organization. I would also love to mentor the students in the next year's program. In totality, I will make sure that I remain connected to the orgaization, and help both the organization, and other contributors which want to work with Open Printing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment