Contributors1 hourIn the Build a web application with Habitat module, you built a basic web application that creates animated GIFs. Here's what you saw:

You may have noticed that the web application supports GIF or PNG source files, but it does not support JPEG files.
In this module, you'll discover the source of the issue and then build your own ImageMagick package that includes support for JPEG images.
Prerequisites
This module builds on the Build a web application with Habitat module. It also requires that you have the Habitat command-line interface (CLI) and Docker on your workstation. We recommend you complete the Build a web application with Habitat module before you begin this one to ensure you're all set up.
Start the Build a web application module
1. Get the sample app
Here you'll download starter code for the web application. The code is similar to what you use in the Build a web application with Habitat module. We provide this version of the source code so you can work through this module in its own environment.
Start by moving to a working directory, for example, your home directory.
Next, clone the habitat-building-dependencies project from GitHub.
Terminal: ~
$ | git clone https://github.com/learn-chef/habitat-building-dependencies
|
Next, move to the habitat-building-dependencies directory.
Terminal: ~
$ | cd ~/habitat-building-dependencies
|
2. Reproduce the issue
In the Build a web application with Habitat module, you built a Habitat package for the web application and exported the package to Docker so that you can access the site from a browser.
Here you'll practice the build and export process. Then you'll bring up the web application and see the failure when you provide a JPEG image. Then you'll inspect the logs to discover what caused the failure.
Start by running hab studio enter to enter the Studio.
Terminal: ~/habitat-building-dependencies
Run build to create the Habitat artifact.
Hab Studio
[1][default:/src:0]# | build
|
Next, run hab pkg export to export the package as a Docker container. Replace the .hart file you see with yours.
Hab Studio
[2][default:/src:0]# | hab pkg export docker ./results/learn-chef-habitatize-0.1.0-20171008041215-x86_64-linux.hart
|
Run exit to leave the Studio.
Hab Studio
[3][default:/src:0]# | exit
|
logout
|
Run the following docker run command to bring up the container. On Windows, remember to replace $HAB_ORIGIN with $env:HAB_ORIGIN.
Terminal: ~/habitat-building-dependencies
$ | docker run -p 8000:8000 $HAB_ORIGIN/habitatize
|
From a web browser, navigate to http://localhost:8000 or http://127.0.0.1:8000. You see this.

Choose a JPEG image from your file system. You can find one in the ~/habitat-building-dependencies directory. Then click Upload image.

You see an "Internal Server Error" response. The page does not show additional details as to why the application has failed. That information can be found in the Supervisor logs. You can find these logs in the terminal session that's running the Docker container.
Return to your terminal and view the logs. You'll discover that ImageMagick was unable to decode the JPEG image format.
Terminal: ~/habitat-building-dependencies
| [...]habitatize.default(O): 172.17.0.1 - - [02/Oct/2017:20:40:09 +0000] "GET / HTTP/1.1" 200 293 0.0075habitatize.default(O): 2017-10-02 20:54:46 - Magick::ImageMagickError - no decode delegate for this image format `JPEG' @ error/constitute.c/ReadImage/501:habitatize.default(O): /hab/pkgs/learn-chef/habitatize/0.1.0/20171002202549/app/vendor/bundle/ruby/2.4.0/gems/rmagick-2.16.0/lib/rmagick_internal.rb:1616:in `read'habitatize.default(O): /hab/pkgs/learn-chef/habitatize/0.1.0/20171002202549/app/vendor/bundle/ruby/2.4.0/gems/rmagick-2.16.0/lib/rmagick_internal.rb:1616:in `block in initialize'habitatize.default(O): /hab/pkgs/learn-chef/habitatize/0.1.0/20171002202549/app/vendor/bundle/ruby/2.4.0/gems/rmagick-2.16.0/lib/rmagick_internal.rb:1615:in `each'[...]
|
You have reproduced the issue and learned a little more about what caused it. Enter Ctrl+C to terminate the Docker container.
3. Create the plan
The web application uses ImageMagick to generate animated GIF images. Recall that the Habitat plan includes a dependency on the core/imagemagick package.
Editor: ~/habitat-building-dependencies/habitat/plan.sh
1
2
3
4
5
| pkg_name=habitatize
pkg_origin=myorigin
pkg_scaffolding="core/scaffolding-ruby"
pkg_version="0.1.0"
pkg_deps=( core/imagemagick ) |
Recall that the "core" origin is the set of foundational packages that are managed and versioned by the core Habitat maintainers. This implementation of ImageMagick does not include support for decoding JPEG images.
In practice, you might work with the package maintainer to see how the package can be updated to meet your requirements. In some cases, the functionality you need goes beyond what the package maintainer had intended. In that case, you can create your own package that does what you need.
Here, you'll create your own ImageMagick package that's built to meet your requirements. You'll use the existing core/imagemagick plan as a starting point.
You can search Habitat Builder for all public packages. From a browser, navigate to bldr.habitat.sh. Then enter imagemagick in the search field.

Select the core/imagemagick package to see more details. These details include how the package is built, its release history, and the source code for the plan file that was used to create it.

The core/imagemagick plan is all you need to recreate this package. From the ~/habitat-building-dependencies directory, create a directory named imagemagick and a file named imagemagick/plan.sh.
Terminal: ~/habitat-building-dependencies
Terminal: ~/habitat-building-dependencies
$ | touch imagemagick/plan.sh
|
| Each plan file is typically located in its own project directory. For learning purposes, you'll use the same project directory for both plans. |
From your text editor, add the contents of the core/imagemagick plan to imagemagick/plan.sh. Then change the value of pkg_origin to your origin. Here's an example.
Editor: ~/habitat-building-dependencies/imagemagick/plan.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| pkg_name=imagemagick
pkg_origin=learn-chef
pkg_version=6.9.2-10
pkg_description="A software suite to create, edit, compose, or convert bitmap images."
pkg_upstream_url="http://imagemagick.org/"
pkg_license=('Apache2')
pkg_maintainer="The Habitat Maintainers <humans@habitat.sh>"
pkg_source=http://www.imagemagick.org/download/releases/ImageMagick-${pkg_version}.tar.xz
pkg_shasum=da2f6fba43d69f20ddb11783f13f77782b0b57783dde9cda39c9e5e733c2013c
pkg_deps=(core/glibc core/zlib core/libpng core/xz core/gcc-libs)
pkg_build_deps=(core/zlib core/coreutils core/diffutils core/patch core/make core/gcc core/sed core/glibc core/pkg-config)
pkg_bin_dirs=(bin)
pkg_include_dirs=(include/ImageMagick-6)
pkg_lib_dirs=(lib)
pkg_dirname=ImageMagick-${pkg_version}
do_build() {
CC="gcc -std=gnu99" ./configure --prefix=$pkg_prefix
make
} |
In practice, you would also update the description and maintainer settings, and possibly the license and other settings.
So far, you have a plan that's identical to the core/imagemagick plan. It does not yet describe how to add JPEG support. Let's build the package to verify that it works.
Run hab studio enter to create a new Studio.
Terminal: ~/habitat-building-dependencies
Build the imagemagick package, like this.
Hab Studio
[1][default:/src:0]# | build imagemagick
|
: Loading /src/imagemagick/plan.sh
|
imagemagick: Plan loaded
|
imagemagick: Validating plan metadata
|
[...]
|
imagemagick: Preparing to build
|
imagemagick: Building
|
checking build system type... x86_64-unknown-linux-gnu
|
checking host system type... x86_64-unknown-linux-gnu
|
checking target system type... x86_64-unknown-linux-gnu
|
checking for a BSD-compatible install... /hab/pkgs/core/coreutils/8.25/20170513213226/bin/install -c
|
checking whether build environment is sane... yes
|
[...]
|
-------------------------------------------------------------
|
checking for JPEG...
|
checking jconfig.h usability... no
|
checking jconfig.h presence... no
|
checking for jconfig.h... no
|
checking jerror.h usability... no
|
checking jerror.h presence... no
|
checking for jerror.h... no
|
checking jmorecfg.h usability... no
|
checking jmorecfg.h presence... no
|
checking for jmorecfg.h... no
|
checking jpeglib.h usability... no
|
checking jpeglib.h presence... no
|
checking for jpeglib.h... no
|
checking for jpeg_read_header in -ljpeg... no
|
checking for JPEG library is version 6b or later... no
|
checking if JPEG package is complete... no
|
-------------------------------------------------------------
|
[...]
|
=============================================================================
|
ImageMagick is configured as follows. Please verify that this configuration
|
matches your expectations.
|
|
Host system type: x86_64-unknown-linux-gnu
|
Build system type: x86_64-unknown-linux-gnu
|
|
Option Value
|
------------------------------------------------------------------------------
|
Shared libraries --enable-shared=yes yes
|
Static libraries --enable-static=yes yes
|
Module support --with-modules=no no
|
[...]
|
Ghostscript lib --with-gslib=no no
|
Graphviz --with-gvc=yes no
|
JBIG --with-jbig=yes no
|
JPEG v1 --with-jpeg=yes no
|
[...]
|
imagemagick: I love it when a plan.sh comes together.
|
imagemagick:
|
imagemagick: Build time: 3m0s
|
The plan for ImageMagick installs all the build dependencies (pkg_build_deps), runtime dependencies (pkg_deps), and then retrieves the application source from the URL specified by pkg_source.
The build is broken down into a number of phases that have default behaviors. In this plan everything is downloaded, verified, and unpacked using these default behaviors. However, this plan overrides the default build phase by implementing the do_buildcallback.
The default build phase configures the software to be built and then builds the software by running:
CC="gcc -std=gnu99" ./configure --prefix=$pkg_prefix
For ImageMagick, the CC environment variable, which describes which compiler to use and how it is configured, is set before executing the ./configure script.
| When you build software on Linux, the --prefix argument typically specifies /usr/local or another common installation location. Here it is set to $pkg_prefix, a plan variable that contains the absolute path for your package because everything in Habitat packages are self-contained. |
This configure script inspects the system to determine if ImageMagick can be built in this environment. During the execution of the configuration script it was unable to find any JPEG files and libraries, for example, jconfig.h and jerror.h.
Now you need to find a package that contains these files and add that package as a runtime dependency.
4. Build ImageMagick with JPEG support
In the previous step, you saw how the ImageMagick build process looked for certain C header files, such as jconfig.h and jerror.h. These files didn't exist in the Studio, so we need to install a package that contains these files. Once such package is core/libjpeg-turbo.
To ensure this package satisfies your runtime dependency needs, you'll need to install it and examine its contents.
| Installing packages that you eventually do not use will not affect your build. An installed package is not automatically included in the build unless it is specifically added to the plan file as a runtime or build dependency. |
Run hab pkg install to install the core/libjpeg-turbo package.
Hab Studio
[3][default:/src:0]# | hab pkg install core/libjpeg-turbo
|
» Installing core/libjpeg-turbo from channel 'stable'
|
☛ Verifying core/libjpeg-turbo/1.5.0/20170513235909
|
→ Using core/glibc/2.22/20170513201042
|
→ Using core/linux-headers/4.3/20170513200956
|
✓ Installed core/libjpeg-turbo/1.5.0/20170513235909
|
★ Install of core/libjpeg-turbo/1.5.0/20170513235909 complete with 1 new packages installed.
|
You can run hab pkg provides to search for a specific file among all installed packages. Search for the file named jconfig.h.
Hab Studio
[4][default:/src:0]# | hab pkg provides jconfig.h
|
core/libjpeg-turbo
|
The result shows that the package core/libjpeg-turbo contains one of the files ImageMagick requires.
Return to the ImageMagick plan file and add core/libjpeg-turbo package to the pkg_deps array.
The entire ImageMagick plan file looks like this.
Editor: ~/habitat-building-dependencies/imagemagick/plan.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| pkg_name=imagemagick
pkg_origin=learn-chef
pkg_version=6.9.2-10
pkg_description="A software suite to create, edit, compose, or convert bitmap images."
pkg_upstream_url="http://imagemagick.org/"
pkg_license=('Apache2')
pkg_maintainer="The Habitat Maintainers <humans@habitat.sh>"
pkg_source=http://www.imagemagick.org/download/releases/ImageMagick-${pkg_version}.tar.xz
pkg_shasum=da2f6fba43d69f20ddb11783f13f77782b0b57783dde9cda39c9e5e733c2013c
pkg_deps=(core/glibc core/zlib core/libpng core/xz core/gcc-libs core/libjpeg-turbo)
pkg_build_deps=(core/zlib core/coreutils core/diffutils core/patch core/make core/gcc core/sed core/glibc core/pkg-config)
pkg_bin_dirs=(bin)
pkg_include_dirs=(include/ImageMagick-6)
pkg_lib_dirs=(lib)
pkg_dirname=ImageMagick-${pkg_version}
do_build() {
CC="gcc -std=gnu99" ./configure --prefix=$pkg_prefix
make
} |
Return to the Studio and build ImageMagick a second time.
Hab Studio
[5][default:/src:0]# | build imagemagick
|
[...]
|
-------------------------------------------------------------
|
checking for JPEG...
|
checking jconfig.h usability... yes
|
checking jconfig.h presence... yes
|
checking for jconfig.h... yes
|
checking jerror.h usability... yes
|
checking jerror.h presence... yes
|
checking for jerror.h... yes
|
checking jmorecfg.h usability... yes
|
checking jmorecfg.h presence... yes
|
checking for jmorecfg.h... yes
|
checking jpeglib.h usability... yes
|
checking jpeglib.h presence... yes
|
checking for jpeglib.h... yes
|
checking for jpeg_read_header in -ljpeg... yes
|
checking for JPEG library is version 6b or later... yes
|
checking if JPEG package is complete... yes
|
-------------------------------------------------------------
|
[...]
|
JBIG --with-jbig=yes no
|
JPEG v1 --with-jpeg=yes yes
|
LCMS --with-lcms=yes no
|
[...]
|
imagemagick: I love it when a plan.sh comes together.
|
imagemagick:
|
imagemagick: Build time: 2m54s
|
The configuration found all the necessary development libraries and enabled JPEG support.
5. Use the updated ImageMagick package
Your ImageMagick package is built to the ~/habitat-building-dependencies/imagemagick/results directory. The build process installs the package for you.
Modify your web application's plan file to use the ImageMagick package you've just built. Because you're adding functionality to your web application, also increment its version number to 0.2.0.
Here's an example. Replace learn-chef with your origin name.
Editor: ~/habitat-building-dependencies/habitat/plan.sh
1
2
3
4
5
| pkg_name=habitatize
pkg_origin=learn-chef
pkg_scaffolding="core/scaffolding-ruby"
pkg_version="0.2.0"
pkg_deps=( learn-chef/imagemagick ) |
From the studio, run build to build the web application.
Hab Studio
[6][default:/src:0]# | build
|
Next, run hab pkg export to export the package to Docker.
Hab Studio
[7][default:/src:0]# | hab pkg export docker ./results/learn-chef-habitatize-0.2.0-20171006142939-x86_64-linux.hart
|
Run exit to leave the Studio.
Hab Studio
[8][default:/src:0]# | exit
|
logout
|
Like you did earlier, run docker run to create a container from the new Docker image. On Windows, remember to replace $HAB_ORIGIN with $env:HAB_ORIGIN.
Terminal: ~/habitat-building-dependencies
$ | docker run -p 8000:8000 $HAB_ORIGIN/habitatize
|
From a web browser, navigate to http://localhost:8000 or http://127.0.0.1:8000.

Specify the JPEG image as you did earlier. You see that the app is now able to successfully produce the animated GIF from your image!

In practice, you might share your work back to the community so others can benefit. For example, you might upload your package to Builder. If you're modifying a package that's maintained by someone else, you might submit a GitHub pull request and ask the maintainers to review your change and publish an updated Habitat package.
Summary
In this module, you added a feature that enables your web application to work with JPEG images. Here's a quick recap:
- You reproduced the issue and examined the log.
- You created a plan for ImageMagick that's based on the core plan.
- You rebuilt ImageMagick to include the
libjpeg-turbo library, which provides support for JPEG images. - You rebuilt your web application to include your version of ImageMagick.
- You verified that the web application supports JPEG images.
In Build a web application with Habitat, you saw how scaffolding can help you get your application running quickly. Here, you got to practice your sleuthing skills by seeing something fail and then exploring what's required to make your app work.