Index: uspace/app/barber/barber.c
===================================================================
--- uspace/app/barber/barber.c	(revision 38f55980b853a6d2953396322e7620146fa59ad2)
+++ uspace/app/barber/barber.c	(revision 0576df9c3cf6dea4ee0796c50c76680c8fafcad7)
@@ -34,9 +34,8 @@
  */
 
-#include <draw/surface.h>
-#include <draw/codec.h>
 #include <device/led_dev.h>
 #include <errno.h>
 #include <fibril_synch.h>
+#include <gfximage/tga_gz.h>
 #include <io/pixel.h>
 #include <loc.h>
@@ -94,5 +93,4 @@
 static fibril_timer_t *frame_timer = NULL;
 static ui_image_t *frame_img;
-static surface_t *frames[FRAMES];
 static gfx_bitmap_t *frame_bmp[FRAMES];
 
@@ -123,31 +121,16 @@
 static bool decode_frames(gfx_context_t *gc)
 {
-	gfx_bitmap_alloc_t alloc;
-	surface_coord_t w, h;
-	gfx_bitmap_params_t params;
+	gfx_rect_t rect;
 	errno_t rc;
 
 	for (unsigned int i = 0; i < FRAMES; i++) {
-		frames[i] = decode_tga_gz(images[i].addr, images[i].size,
-		    SURFACE_FLAG_SHARED);
-		if (frames[i] == NULL) {
+		rc = decode_tga_gz(gc, images[i].addr, images[i].size,
+		    &frame_bmp[i], &rect);
+		if (rc != EOK) {
 			printf("Unable to decode frame %u.\n", i);
 			return false;
 		}
 
-		surface_get_resolution(frames[i], &w, &h);
-		gfx_bitmap_params_init(&params);
-		params.rect.p1.x = w;
-		params.rect.p1.y = h;
-
-		alloc.pitch = sizeof(uint32_t) * w;
-		alloc.off0 = 0;
-		alloc.pixels = surface_direct_access(frames[i]);
-
-		rc = gfx_bitmap_create(gc, &params, &alloc, &frame_bmp[i]);
-		if (rc != EOK) {
-			printf("Error creating bitmap.\n");
-			return false;
-		}
+		(void) rect;
 	}
 
@@ -162,7 +145,4 @@
 		gfx_bitmap_destroy(frame_bmp[i]);
 		frame_bmp[i] = NULL;
-
-		surface_destroy(frames[i]);
-		frames[i] = NULL;
 	}
 }
Index: uspace/app/barber/meson.build
===================================================================
--- uspace/app/barber/meson.build	(revision 38f55980b853a6d2953396322e7620146fa59ad2)
+++ uspace/app/barber/meson.build	(revision 0576df9c3cf6dea4ee0796c50c76680c8fafcad7)
@@ -27,5 +27,5 @@
 #
 
-deps = [ 'ui', 'draw', 'compress' ]
+deps = [ 'ui', 'gfximage', 'compress' ]
 
 _images = files(
Index: uspace/app/launcher/launcher.c
===================================================================
--- uspace/app/launcher/launcher.c	(revision 38f55980b853a6d2953396322e7620146fa59ad2)
+++ uspace/app/launcher/launcher.c	(revision 0576df9c3cf6dea4ee0796c50c76680c8fafcad7)
@@ -36,4 +36,5 @@
 #include <errno.h>
 #include <gfx/coord.h>
+#include <gfximage/tga.h>
 #include <stdbool.h>
 #include <stdio.h>
@@ -42,10 +43,4 @@
 #include <str_error.h>
 #include <task.h>
-
-#include <draw/surface.h>
-#include <draw/source.h>
-#include <draw/drawctx.h>
-#include <draw/codec.h>
-
 #include <ui/fixed.h>
 #include <ui/image.h>
@@ -157,9 +152,8 @@
 	gfx_bitmap_params_t logo_params;
 	gfx_bitmap_t *logo_bmp;
-	gfx_bitmap_alloc_t alloc;
 	gfx_context_t *gc;
-	surface_coord_t w, h;
 	gfx_rect_t logo_rect;
 	gfx_rect_t rect;
+	gfx_coord2_t off;
 	errno_t rc;
 
@@ -182,11 +176,4 @@
 	}
 
-	surface_t *logo = decode_tga((void *) helenos_tga, helenos_tga_size,
-	    SURFACE_FLAG_SHARED);
-	if (!logo) {
-		printf("Unable to decode logo.\n");
-		return 1;
-	}
-
 	rc = ui_create(display_spec, &ui);
 	if (rc != EOK) {
@@ -217,19 +204,13 @@
 	gc = ui_window_get_gc(window);
 
-	surface_get_resolution(logo, &w, &h);
+	rc = decode_tga(gc, (void *) helenos_tga, helenos_tga_size,
+	    &logo_bmp, &logo_rect);
+	if (rc != EOK) {
+		printf("Unable to decode logo.\n");
+		return 1;
+	}
+
 	gfx_bitmap_params_init(&logo_params);
-	logo_params.rect.p1.x = w;
-	logo_params.rect.p1.y = h;
-	logo_rect = logo_params.rect;
-
-	alloc.pitch = sizeof(uint32_t) * w;
-	alloc.off0 = 0;
-	alloc.pixels = surface_direct_access(logo);
-
-	rc = gfx_bitmap_create(gc, &logo_params, &alloc, &logo_bmp);
-	if (rc  != EOK) {
-		printf("Error creating bitmap.\n");
-		return 1;
-	}
+	logo_params.rect = logo_rect;
 
 	rc = ui_fixed_create(&launcher.fixed);
@@ -245,8 +226,7 @@
 	}
 
-	rect.p0.x = 5;
-	rect.p0.y = 32;
-	rect.p1.x = 5 + w;
-	rect.p1.y = 32 + h;
+	off.x = 5;
+	off.y = 32;
+	gfx_rect_translate(&off, &logo_rect, &rect);
 	ui_image_set_rect(launcher.image, &rect);
 
Index: uspace/app/launcher/meson.build
===================================================================
--- uspace/app/launcher/meson.build	(revision 38f55980b853a6d2953396322e7620146fa59ad2)
+++ uspace/app/launcher/meson.build	(revision 0576df9c3cf6dea4ee0796c50c76680c8fafcad7)
@@ -27,5 +27,5 @@
 #
 
-deps = [ 'draw', 'ui' ]
+deps = [ 'gfximage', 'ui' ]
 
 _images = files('gfx/helenos.tga')
Index: uspace/app/viewer/meson.build
===================================================================
--- uspace/app/viewer/meson.build	(revision 38f55980b853a6d2953396322e7620146fa59ad2)
+++ uspace/app/viewer/meson.build	(revision 0576df9c3cf6dea4ee0796c50c76680c8fafcad7)
@@ -27,5 +27,5 @@
 #
 
-deps = [ 'ui', 'draw', 'compress' ]
+deps = [ 'ui', 'gfximage', 'compress' ]
 src = files('viewer.c')
 
Index: uspace/app/viewer/viewer.c
===================================================================
--- uspace/app/viewer/viewer.c	(revision 38f55980b853a6d2953396322e7620146fa59ad2)
+++ uspace/app/viewer/viewer.c	(revision 0576df9c3cf6dea4ee0796c50c76680c8fafcad7)
@@ -34,7 +34,6 @@
  */
 
-#include <draw/surface.h>
-#include <draw/codec.h>
 #include <errno.h>
+#include <gfximage/tga.h>
 #include <stdbool.h>
 #include <stdio.h>
@@ -58,13 +57,13 @@
 
 static ui_window_t *window;
-static surface_t *surface = NULL;
+static gfx_bitmap_t *bitmap = NULL;
 static ui_image_t *image = NULL;
 static gfx_context_t *window_gc;
 
-static surface_coord_t img_width;
-static surface_coord_t img_height;
-
-static bool img_load(const char *, surface_t **);
-static bool img_setup(gfx_context_t *, surface_t *);
+static gfx_rect_t img_rect;
+
+static bool img_load(gfx_context_t *gc, const char *, gfx_bitmap_t **,
+    gfx_rect_t *);
+static bool img_setup(gfx_context_t *, gfx_bitmap_t *, gfx_rect_t *);
 
 static void wnd_close(ui_window_t *, void *);
@@ -115,11 +114,12 @@
 
 	if (update) {
-		surface_t *lsface;
-
-		if (!img_load(imgs[imgs_current], &lsface)) {
+		gfx_bitmap_t *lbitmap;
+		gfx_rect_t lrect;
+
+		if (!img_load(window_gc, imgs[imgs_current], &lbitmap, &lrect)) {
 			printf("Cannot load image \"%s\".\n", imgs[imgs_current]);
 			exit(4);
 		}
-		if (!img_setup(window_gc, lsface)) {
+		if (!img_setup(window_gc, lbitmap, &lrect)) {
 			printf("Cannot setup image \"%s\".\n", imgs[imgs_current]);
 			exit(6);
@@ -128,5 +128,6 @@
 }
 
-static bool img_load(const char *fname, surface_t **p_local_surface)
+static bool img_load(gfx_context_t *gc, const char *fname,
+    gfx_bitmap_t **rbitmap, gfx_rect_t *rect)
 {
 	int fd;
@@ -158,6 +159,6 @@
 	vfs_put(fd);
 
-	*p_local_surface = decode_tga(tga, stat.size, SURFACE_FLAG_SHARED);
-	if (*p_local_surface == NULL) {
+	rc = decode_tga(gc, tga, stat.size, rbitmap, rect);
+	if (rc != EOK) {
 		free(tga);
 		return false;
@@ -166,15 +167,10 @@
 	free(tga);
 
-	surface_get_resolution(*p_local_surface, &img_width, &img_height);
-
+	img_rect = *rect;
 	return true;
 }
 
-static bool img_setup(gfx_context_t *gc, surface_t *local_surface)
-{
-	surface_coord_t w, h;
-	gfx_bitmap_params_t params;
-	gfx_bitmap_alloc_t alloc;
-	gfx_bitmap_t *bmp;
+static bool img_setup(gfx_context_t *gc, gfx_bitmap_t *bmp, gfx_rect_t *rect)
+{
 	gfx_rect_t arect;
 	gfx_rect_t irect;
@@ -184,31 +180,15 @@
 	ui_res = ui_window_get_res(window);
 
-	surface_get_resolution(local_surface, &w, &h);
-	gfx_bitmap_params_init(&params);
-	params.rect.p1.x = w;
-	params.rect.p1.y = h;
-
 	ui_window_get_app_rect(window, &arect);
-	gfx_rect_translate(&arect.p0, &params.rect, &irect);
-
-	alloc.pitch = sizeof(uint32_t) * w;
-	alloc.off0 = 0;
-	alloc.pixels = surface_direct_access(local_surface);
-
-	rc = gfx_bitmap_create(gc, &params, &alloc, &bmp);
-	if (rc != EOK) {
-		surface_destroy(local_surface);
-		return false;
-	}
+	gfx_rect_translate(&arect.p0, rect, &irect);
 
 	if (image != NULL) {
-		ui_image_set_bmp(image, bmp, &params.rect);
+		ui_image_set_bmp(image, bmp, rect);
 		(void) ui_image_paint(image);
 		ui_image_set_rect(image, &irect);
 	} else {
-		rc = ui_image_create(ui_res, bmp, &params.rect, &image);
+		rc = ui_image_create(ui_res, bmp, rect, &image);
 		if (rc != EOK) {
 			gfx_bitmap_destroy(bmp);
-			surface_destroy(local_surface);
 			return false;
 		}
@@ -218,8 +198,8 @@
 	}
 
-	if (surface != NULL)
-		surface_destroy(surface);
-
-	surface = local_surface;
+	if (bitmap != NULL)
+		gfx_bitmap_destroy(bitmap);
+
+	bitmap = bmp;
 	return true;
 }
@@ -235,5 +215,6 @@
 {
 	const char *display_spec = DISPLAY_DEFAULT;
-	surface_t *lsface;
+	gfx_bitmap_t *lbitmap;
+	gfx_rect_t lrect;
 	bool fullscreen = false;
 	gfx_rect_t rect;
@@ -287,9 +268,4 @@
 	}
 
-	if (!img_load(imgs[imgs_current], &lsface)) {
-		printf("Cannot load image \"%s\".\n", imgs[imgs_current]);
-		return 1;
-	}
-
 	// TODO Fullscreen mode
 	if (fullscreen) {
@@ -306,30 +282,44 @@
 	viewer.ui = ui;
 
-	rect.p0.x = 0;
-	rect.p0.y = 0;
-	rect.p1.x = img_width;
-	rect.p1.y = img_height;
-
+	/*
+	 * We don't know the image size yet, so create tiny window and resize
+	 * later.
+	 */
 	ui_wnd_params_init(&params);
 	params.caption = "Viewer";
+	params.rect.p0.x = 0;
+	params.rect.p0.y = 0;
+	params.rect.p1.x = 1;
+	params.rect.p1.y = 1;
+
+	rc = ui_window_create(ui, &params, &window);
+	if (rc != EOK) {
+		printf("Error creating window.\n");
+		return 1;
+	}
+
+	window_gc = ui_window_get_gc(window);
+
+	ui_window_set_cb(window, &window_cb, (void *) &viewer);
+
+	if (!img_load(window_gc, imgs[imgs_current], &lbitmap, &lrect)) {
+		printf("Cannot load image \"%s\".\n", imgs[imgs_current]);
+		return 1;
+	}
+
 	/*
 	 * Compute window rectangle such that application area corresponds
 	 * to rect
 	 */
-	ui_wdecor_rect_from_app(&rect, &wrect);
+	ui_wdecor_rect_from_app(&lrect, &wrect);
 	off = wrect.p0;
-	gfx_rect_rtranslate(&off, &wrect, &params.rect);
-
-	rc = ui_window_create(ui, &params, &window);
-	if (rc != EOK) {
-		printf("Error creating window.\n");
-		return 1;
-	}
-
-	window_gc = ui_window_get_gc(window);
-
-	ui_window_set_cb(window, &window_cb, (void *) &viewer);
-
-	if (!img_setup(window_gc, lsface)) {
+	gfx_rect_rtranslate(&off, &wrect, &rect);
+	rc = ui_window_resize(window, &rect);
+	if (rc != EOK) {
+		printf("Error resizing window.\n");
+		return 1;
+	}
+
+	if (!img_setup(window_gc, lbitmap, &lrect)) {
 		printf("Cannot setup image \"%s\".\n", imgs[imgs_current]);
 		return 1;
Index: uspace/lib/gfximage/doc/doxygroups.h
===================================================================
--- uspace/lib/gfximage/doc/doxygroups.h	(revision 0576df9c3cf6dea4ee0796c50c76680c8fafcad7)
+++ uspace/lib/gfximage/doc/doxygroups.h	(revision 0576df9c3cf6dea4ee0796c50c76680c8fafcad7)
@@ -0,0 +1,3 @@
+/** @addtogroup libgfximage libgfximage
+ * @ingroup libs
+ */
Index: uspace/lib/gfximage/include/gfximage/tga.h
===================================================================
--- uspace/lib/gfximage/include/gfximage/tga.h	(revision 0576df9c3cf6dea4ee0796c50c76680c8fafcad7)
+++ uspace/lib/gfximage/include/gfximage/tga.h	(revision 0576df9c3cf6dea4ee0796c50c76680c8fafcad7)
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2020 Jiri Svoboda
+ * Copyright (c) 2014 Martin Decky
+ * Copyright (c) 2011 Petr Koupy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup draw
+ * @{
+ */
+/**
+ * @file
+ */
+
+#ifndef GFXIMAGE_TGA_H_
+#define GFXIMAGE_TGA_H_
+
+#include <errno.h>
+#include <gfx/context.h>
+#include <gfx/coord.h>
+#include <stddef.h>
+
+extern errno_t decode_tga(gfx_context_t *, void *, size_t,
+    gfx_bitmap_t **, gfx_rect_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/gfximage/include/gfximage/tga_gz.h
===================================================================
--- uspace/lib/gfximage/include/gfximage/tga_gz.h	(revision 0576df9c3cf6dea4ee0796c50c76680c8fafcad7)
+++ uspace/lib/gfximage/include/gfximage/tga_gz.h	(revision 0576df9c3cf6dea4ee0796c50c76680c8fafcad7)
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2020 Jiri Svoboda
+ * Copyright (c) 2014 Martin Decky
+ * Copyright (c) 2011 Petr Koupy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup draw
+ * @{
+ */
+/**
+ * @file
+ */
+
+#ifndef GFXIMAGE_TGA_GZ_H_
+#define GFXIMAGE_TGA_GZ_H_
+
+#include <errno.h>
+#include <gfx/context.h>
+#include <gfx/coord.h>
+#include <stddef.h>
+
+extern errno_t decode_tga_gz(gfx_context_t *, void *, size_t,
+    gfx_bitmap_t **, gfx_rect_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/gfximage/meson.build
===================================================================
--- uspace/lib/gfximage/meson.build	(revision 0576df9c3cf6dea4ee0796c50c76680c8fafcad7)
+++ uspace/lib/gfximage/meson.build	(revision 0576df9c3cf6dea4ee0796c50c76680c8fafcad7)
@@ -0,0 +1,33 @@
+#
+# Copyright (c) 2020 Jiri Svoboda
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+deps = [ 'gfx', 'softrend' , 'compress' ]
+src = files(
+	'src/tga.c',
+	'src/tga_gz.c',
+)
Index: uspace/lib/gfximage/src/tga.c
===================================================================
--- uspace/lib/gfximage/src/tga.c	(revision 0576df9c3cf6dea4ee0796c50c76680c8fafcad7)
+++ uspace/lib/gfximage/src/tga.c	(revision 0576df9c3cf6dea4ee0796c50c76680c8fafcad7)
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2011 Martin Decky
+ * Copyright (c) 2011 Petr Koupy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup draw
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include <stdlib.h>
+#include <byteorder.h>
+#include <align.h>
+#include <stdbool.h>
+#include <pixconv.h>
+#include <gfx/bitmap.h>
+#include <gfximage/tga.h>
+#include <io/pixelmap.h>
+
+typedef struct {
+	uint8_t id_length;
+	uint8_t cmap_type;
+	uint8_t img_type;
+
+	uint16_t cmap_first_entry;
+	uint16_t cmap_entries;
+	uint8_t cmap_bpp;
+
+	uint16_t startx;
+	uint16_t starty;
+	uint16_t width;
+	uint16_t height;
+	uint8_t img_bpp;
+	uint8_t img_descr;
+} __attribute__((packed)) tga_header_t;
+
+typedef enum {
+	CMAP_NOT_PRESENT = 0,
+	CMAP_PRESENT = 1,
+	CMAP_RESERVED_START = 2,
+	CMAP_PRIVATE_START = 128
+} cmap_type_t;
+
+typedef enum {
+	IMG_EMTPY = 0,
+	IMG_CMAP = 1,
+	IMG_BGRA = 2,
+	IMG_GRAY = 3,
+	IMG_CMAP_RLE = 9,
+	IMG_BGRA_RLE = 10,
+	IMG_GRAY_RLE = 11
+} img_type_t;
+
+typedef struct {
+	cmap_type_t cmap_type;
+	img_type_t img_type;
+
+	uint16_t cmap_first_entry;
+	uint16_t cmap_entries;
+	uint8_t cmap_bpp;
+
+	uint16_t startx;
+	uint16_t starty;
+	uint16_t width;
+	uint16_t height;
+	uint8_t img_bpp;
+	uint8_t img_alpha_bpp;
+	uint8_t img_alpha_dir;
+
+	void *id_data;
+	size_t id_length;
+
+	void *cmap_data;
+	size_t cmap_length;
+
+	void *img_data;
+	size_t img_length;
+} tga_t;
+
+/** Decode Truevision TGA header
+ *
+ * @param[in]  data Memory representation of TGA.
+ * @param[in]  size Size of the representation (in bytes).
+ * @param[out] tga  Decoded TGA.
+ *
+ * @return True on succesful decoding.
+ * @return False on failure.
+ *
+ */
+static bool decode_tga_header(void *data, size_t size, tga_t *tga)
+{
+	/* Header sanity check */
+	if (size < sizeof(tga_header_t))
+		return false;
+
+	tga_header_t *head = (tga_header_t *) data;
+
+	/* Image ID field */
+	tga->id_data = data + sizeof(tga_header_t);
+	tga->id_length = head->id_length;
+
+	if (size < sizeof(tga_header_t) + tga->id_length)
+		return false;
+
+	/* Color map type */
+	tga->cmap_type = head->cmap_type;
+
+	/* Image type */
+	tga->img_type = head->img_type;
+
+	/* Color map specification */
+	tga->cmap_first_entry = uint16_t_le2host(head->cmap_first_entry);
+	tga->cmap_entries = uint16_t_le2host(head->cmap_entries);
+	tga->cmap_bpp = head->cmap_bpp;
+	tga->cmap_data = tga->id_data + tga->id_length;
+	tga->cmap_length = ALIGN_UP(tga->cmap_entries * tga->cmap_bpp, 8) >> 3;
+
+	if (size < sizeof(tga_header_t) + tga->id_length +
+	    tga->cmap_length)
+		return false;
+
+	/* Image specification */
+	tga->startx = uint16_t_le2host(head->startx);
+	tga->starty = uint16_t_le2host(head->starty);
+	tga->width = uint16_t_le2host(head->width);
+	tga->height = uint16_t_le2host(head->height);
+	tga->img_bpp = head->img_bpp;
+	tga->img_alpha_bpp = head->img_descr & 0x0f;
+	tga->img_alpha_dir = (head->img_descr & 0xf0) >> 4;
+	tga->img_data = tga->cmap_data + tga->cmap_length;
+	tga->img_length = ALIGN_UP(tga->width * tga->height * tga->img_bpp, 8) >> 3;
+
+	if (size < sizeof(tga_header_t) + tga->id_length +
+	    tga->cmap_length + tga->img_length)
+		return false;
+
+	return true;
+}
+
+/** Decode Truevision TGA format
+ *
+ * Decode Truevision TGA format and create a surface
+ * from it. The supported variants of TGA are currently
+ * limited to uncompressed 24 bit true-color images without
+ * alpha channel.
+ *
+ * @param gc      Graphic context
+ * @param data    Memory representation of gzipped TGA.
+ * @param size    Size of the representation (in bytes).
+ * @param rbitmap Place to store pointer to new bitmap
+ * @param rrect   Place to store bitmap rectangle
+ *
+ * @return EOK un success or an error code
+ */
+errno_t decode_tga(gfx_context_t *gc, void *data, size_t size,
+    gfx_bitmap_t **rbitmap, gfx_rect_t *rrect)
+{
+	gfx_bitmap_params_t params;
+	gfx_bitmap_alloc_t alloc;
+	gfx_bitmap_t *bitmap = NULL;
+	pixelmap_t pixelmap;
+	errno_t rc;
+
+	tga_t tga;
+	if (!decode_tga_header(data, size, &tga))
+		return EINVAL;
+
+	/*
+	 * Check for unsupported features.
+	 */
+
+	switch (tga.cmap_type) {
+	case CMAP_NOT_PRESENT:
+		break;
+	default:
+		/* Unsupported */
+		return ENOTSUP;
+	}
+
+	switch (tga.img_type) {
+	case IMG_BGRA:
+		if (tga.img_bpp != 24)
+			return ENOTSUP;
+		break;
+	case IMG_GRAY:
+		if (tga.img_bpp != 8)
+			return ENOTSUP;
+		break;
+	default:
+		/* Unsupported */
+		return ENOTSUP;
+	}
+
+	if (tga.img_alpha_bpp != 0)
+		return ENOTSUP;
+
+	sysarg_t twidth = tga.startx + tga.width;
+	sysarg_t theight = tga.starty + tga.height;
+
+	gfx_bitmap_params_init(&params);
+	params.rect.p1.x = twidth;
+	params.rect.p1.y = theight;
+
+	rc = gfx_bitmap_create(gc, &params, NULL, &bitmap);
+	if (rc != EOK)
+		return rc;
+
+	rc = gfx_bitmap_get_alloc(bitmap, &alloc);
+	if (rc != EOK) {
+		gfx_bitmap_destroy(bitmap);
+		return rc;
+	}
+
+	pixelmap.width = twidth;
+	pixelmap.height = theight;
+	pixelmap.data = alloc.pixels;
+
+	/*
+	 * TGA is encoded in a bottom-up manner, the true-color
+	 * variant is in BGR 8:8:8 encoding.
+	 */
+
+	switch (tga.img_type) {
+	case IMG_BGRA:
+		for (sysarg_t y = tga.starty; y < theight; y++) {
+			for (sysarg_t x = tga.startx; x < twidth; x++) {
+				size_t offset =
+				    ((y - tga.starty) * tga.width + (x - tga.startx)) * 3;
+
+				pixel_t pixel =
+				    bgr_888_2pixel(((uint8_t *) tga.img_data) + offset);
+				pixelmap_put_pixel(&pixelmap, x, theight - y - 1, pixel);
+			}
+		}
+		break;
+	case IMG_GRAY:
+		for (sysarg_t y = tga.starty; y < theight; y++) {
+			for (sysarg_t x = tga.startx; x < twidth; x++) {
+				size_t offset =
+				    (y - tga.starty) * tga.width + (x - tga.startx);
+
+				pixel_t pixel =
+				    gray_8_2pixel(((uint8_t *) tga.img_data) + offset);
+				pixelmap_put_pixel(&pixelmap, x, theight - y - 1, pixel);
+			}
+		}
+		break;
+	default:
+		break;
+	}
+
+	*rbitmap = bitmap;
+	*rrect = params.rect;
+	return EOK;
+}
+
+/** @}
+ */
Index: uspace/lib/gfximage/src/tga_gz.c
===================================================================
--- uspace/lib/gfximage/src/tga_gz.c	(revision 0576df9c3cf6dea4ee0796c50c76680c8fafcad7)
+++ uspace/lib/gfximage/src/tga_gz.c	(revision 0576df9c3cf6dea4ee0796c50c76680c8fafcad7)
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2014 Martin Decky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup draw
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include <errno.h>
+#include <gzip.h>
+#include <stdlib.h>
+#include <gfximage/tga.h>
+#include <gfximage/tga_gz.h>
+
+/** Decode gzipped Truevision TGA format
+ *
+ * Decode gzipped Truevision TGA format and create a bitmap
+ * from it. The supported variants of TGA are limited those
+ * supported by decode_tga().
+ *
+ * @param gc      Graphic context
+ * @param data    Memory representation of gzipped TGA.
+ * @param size    Size of the representation (in bytes).
+ * @param rbitmap Place to store pointer to new bitmap
+ * @param rrect   Place to store bitmap rectangle
+ *
+ * @return EOK un success or an error code
+ */
+errno_t decode_tga_gz(gfx_context_t *gc, void *data, size_t size,
+    gfx_bitmap_t **rbitmap, gfx_rect_t *rrect)
+{
+	void *data_expanded;
+	size_t size_expanded;
+	errno_t rc;
+
+	rc = gzip_expand(data, size, &data_expanded, &size_expanded);
+	if (rc != EOK)
+		return rc;
+
+	rc = decode_tga(gc, data_expanded, size_expanded, rbitmap, rrect);
+	free(data_expanded);
+	return rc;
+}
+
+/** @}
+ */
Index: uspace/lib/meson.build
===================================================================
--- uspace/lib/meson.build	(revision 38f55980b853a6d2953396322e7620146fa59ad2)
+++ uspace/lib/meson.build	(revision 0576df9c3cf6dea4ee0796c50c76680c8fafcad7)
@@ -83,4 +83,5 @@
 	'ext4',
 	'gfxfont',
+	'gfximage',
 	'hound',
 	'ipcgfx',
Index: uspace/lib/ui/include/ui/window.h
===================================================================
--- uspace/lib/ui/include/ui/window.h	(revision 38f55980b853a6d2953396322e7620146fa59ad2)
+++ uspace/lib/ui/include/ui/window.h	(revision 0576df9c3cf6dea4ee0796c50c76680c8fafcad7)
@@ -53,4 +53,5 @@
 extern void ui_window_add(ui_window_t *, ui_control_t *);
 extern void ui_window_remove(ui_window_t *, ui_control_t *);
+extern errno_t ui_window_resize(ui_window_t *, gfx_rect_t *);
 extern ui_resource_t *ui_window_get_res(ui_window_t *);
 extern gfx_context_t *ui_window_get_gc(ui_window_t *);
Index: uspace/lib/ui/src/window.c
===================================================================
--- uspace/lib/ui/src/window.c	(revision 38f55980b853a6d2953396322e7620146fa59ad2)
+++ uspace/lib/ui/src/window.c	(revision 0576df9c3cf6dea4ee0796c50c76680c8fafcad7)
@@ -215,4 +215,39 @@
 }
 
+/** Resize/move window.
+ *
+ * Resize window to the dimensions of @a rect. If @a rect.p0 is not 0,0,
+ * the top-left corner of the window will move on the screen accordingly.
+ *
+ * @param window Window
+ * @param rect Rectangle
+ *
+ * @return EOK on success or an error code
+ */
+errno_t ui_window_resize(ui_window_t *window, gfx_rect_t *rect)
+{
+	gfx_coord2_t offs;
+	gfx_rect_t nrect;
+	errno_t rc;
+
+	/*
+	 * Move rect so that p0=0,0 - keep window's coordinate system origin
+	 * locked to top-left corner of the window.
+	 */
+	offs = rect->p0;
+	gfx_rect_rtranslate(&offs, rect, &nrect);
+
+	/* dwindow can be NULL in case of unit tests */
+	if (window->dwindow != NULL) {
+		rc = display_window_resize(window->dwindow, &offs, &nrect);
+		if (rc != EOK)
+			return rc;
+	}
+
+	ui_wdecor_set_rect(window->wdecor, &nrect);
+	ui_wdecor_paint(window->wdecor);
+	return EOK;
+}
+
 /** Set window callbacks.
  *
Index: uspace/lib/ui/test/window.c
===================================================================
--- uspace/lib/ui/test/window.c	(revision 38f55980b853a6d2953396322e7620146fa59ad2)
+++ uspace/lib/ui/test/window.c	(revision 0576df9c3cf6dea4ee0796c50c76680c8fafcad7)
@@ -175,4 +175,38 @@
 }
 
+/** ui_window_resize */
+PCUT_TEST(resize)
+{
+	errno_t rc;
+	ui_t *ui = NULL;
+	ui_wnd_params_t params;
+	ui_window_t *window = NULL;
+	gfx_rect_t nrect;
+
+	rc = ui_create_disp(NULL, &ui);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	ui_wnd_params_init(&params);
+	params.caption = "Hello";
+	params.rect.p0.x = 0;
+	params.rect.p0.y = 0;
+	params.rect.p1.x = 1;
+	params.rect.p1.y = 1;
+
+	rc = ui_window_create(ui, &params, &window);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+	PCUT_ASSERT_NOT_NULL(window);
+
+	nrect.p0.x = -1;
+	nrect.p0.y = -1;
+	nrect.p1.x = 2;
+	nrect.p1.y = 2;
+	rc = ui_window_resize(window, &nrect);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	ui_window_destroy(window);
+	ui_destroy(ui);
+}
+
 /** ui_window_get_res/gc/rect() return valid objects */
 PCUT_TEST(get_res_gc_rect)
