static bool
create_icon(int filec, Image **in_image, char *outname, bool icon_mode, int32_t hotspot_x, int32_t hotspot_y, int32_t alpha_threshold, int32_t bit_count)
{
	struct {
		Image *in;
		uint32_t bit_count;
		uint32_t palette_count;
		uint32_t image_size;
		uint32_t mask_size;
		uint32_t width;
		uint32_t height;
		uint8_t *image_data;
		Palette *palette;
	} *img;

	Win32CursorIconFileDir dir;
	FILE *out;
	uint32_t c, d, x;
	uint32_t dib_start;
        unsigned char *row, *alpha;

	img = xcalloc(filec * sizeof(*img));

	for (c = 0; c < filec; c++) {
		char header[8];
		uint8_t transparency[256];
		uint16_t transparency_count;
		bool need_transparency;

		img[c].in = in_image[c];

    	if (img[c].in == NULL) {
        	warn_errno("void image");
			goto cleanup;
		}

	        img[c].width = img[c].in->width;
		img[c].height = img[c].in->height;
		img[c].palette = palette_new();


		/* Count number of necessary colors in palette and number of transparencies */
		memset(transparency, 0, 256);
		for (d = 0; d < img[c].height; d++) {
		        row = img[c].in->data + 3 * d * img[c].width;
                        if (img[c].in->alpha)
                            alpha = img[c].in->data + d * img[c].width;
			for (x = 0; x < img[c].width; x++) {
				if (palette_count(img[c].palette) <= (1 << 8))
				    palette_add(img[c].palette, row[3*x+0], row[3*x+1], row[3*x+2]);
				if (1==1)
				    transparency[row[4*x+3]] = 1;
			}
		}
		transparency_count = 0;
		for (d = 0; d < 256; d++)
		    transparency_count += transparency[d];

		/* If there are more than two steps of transparency, or if the
		 * two steps are NOT either entirely off (0) and entirely on (255),
		 * then we will lose transparency information if bit_count is not 32.
		 */
		need_transparency =
		    transparency_count > 2
		    ||
		    (transparency_count == 2 && (transparency[0] == 0 || transparency[255] == 0));

		/* Can we keep all colors in a palette? */
		if (need_transparency) {
			if (bit_count != -1) {
			    if (bit_count != 32)
				warn("decreasing bit depth will discard variable transparency", transparency_count);
			    /* Why 24 and not bit_count? Otherwise we might decrease below what's possible
			           * due to number of colors in image. The real decrease happens below. */
			    img[c].bit_count = 24;
			} else {
			    img[c].bit_count = 32;
			}
			img[c].palette_count = 0;
		}
		else if (palette_count(img[c].palette) <= 256) {
			for (d = 1; palette_count(img[c].palette) > 1 << d; d <<= 1);
			if (d == 2)	/* four colors (two bits) are not supported */
				d = 4;
			img[c].bit_count = d;
			img[c].palette_count = 1 << d;
		}
		else {
			img[c].bit_count = 24;
			img[c].palette_count = 0;
		}

		/* Does the user want to change number of bits per pixel? */
		if (bit_count != -1) {
			if (img[c].bit_count == bit_count) {
				/* No operation */
			} else if (img[c].bit_count < bit_count) {
				img[c].bit_count = bit_count;
				img[c].palette_count = (bit_count > 16 ? 0 : 1 << bit_count);
			} else {
				warn("cannot decrease bit depth from %d to %d, bit depth not changed", img[c].bit_count, bit_count);
			}
		}
		
		img[c].image_size = img[c].height * ROW_BYTES(img[c].width * img[c].bit_count);
		img[c].mask_size = img[c].height * ROW_BYTES(img[c].width);

	}

        out = fopen(outname, "w");
	if (out == NULL) {
		warn_errno("cannot create file");
		goto cleanup;
	}

	dir.reserved = 0;
	dir.type = (icon_mode ? 1 : 2);
	dir.count = filec;
	fix_win32_cursor_icon_file_dir_endian(&dir);
	if (fwrite(&dir, sizeof(Win32CursorIconFileDir), 1, out) != 1) {
		warn_errno("cannot write to file");
		goto cleanup;
	}

	dib_start = sizeof(Win32CursorIconFileDir) + filec * sizeof(Win32CursorIconFileDirEntry);
	for (c = 0; c < filec; c++) {
		Win32CursorIconFileDirEntry entry;

		entry.width = MIN(255, img[c].width);
		entry.height = MIN(255, img[c].height);
		entry.reserved = 0;
		if (icon_mode) {
			entry.hotspot_x = 0;	 /* some mistake this for planes (XXX) */
			entry.hotspot_y = 0;	 /* some mistake this for bit_count (XXX) */
		} else {
			entry.hotspot_x = hotspot_x;	 /* some mistake this for planes (XXX) */
			entry.hotspot_y = hotspot_y;	 /* some mistake this for bit_count (XXX) */
		}
		entry.dib_offset = dib_start;
		entry.color_count = (img[c].bit_count >= 8 ? 0 : 1 << img[c].bit_count);
		entry.dib_size = img[c].palette_count * sizeof(Win32RGBQuad)
				+ sizeof(Win32BitmapInfoHeader)
				+ img[c].image_size
				+ img[c].mask_size;

		dib_start += entry.dib_size;

		fix_win32_cursor_icon_file_dir_entry_endian(&entry);
		if (fwrite(&entry, sizeof(Win32CursorIconFileDirEntry), 1, out) != 1) {
			warn_errno("cannot write to file");
			goto cleanup;
		}

	}

	for (c = 0; c < filec; c++) {
		Win32BitmapInfoHeader bitmap;

		bitmap.size = sizeof(Win32BitmapInfoHeader);
		bitmap.width = png_get_image_width(img[c].png_ptr, img[c].info_ptr);
		bitmap.height = png_get_image_height(img[c].png_ptr, img[c].info_ptr) * 2;
		bitmap.planes = 1;							// appears to be 1 always (XXX)
		bitmap.bit_count = img[c].bit_count;
		bitmap.compression = 0;
		bitmap.x_pels_per_meter = 0;				// should be 0 always
		bitmap.y_pels_per_meter = 0;				// should be 0 always
		bitmap.clr_important = 0;					// should be 0 always
		bitmap.clr_used = img[c].palette_count;
		bitmap.size_image = img[c].image_size;		// appears to be ok here (may be image_size+mask_size or 0, XXX)

		fix_win32_bitmap_info_header_endian(&bitmap);
		if (fwrite(&bitmap, sizeof(Win32BitmapInfoHeader), 1, out) != 1) {
			warn_errno("cannot write to file");
			goto cleanup;
		}

		if (img[c].bit_count <= 16) {
			Win32RGBQuad color;

			palette_assign_indices(img[c].palette);
			color.reserved = 0;
			while (palette_next(img[c].palette, &color.red, &color.green, &color.blue))
				fwrite(&color, sizeof(Win32RGBQuad), 1, out);

			/* Pad with empty colors. The reason we do this is because we
			 * specify bitmap.clr_used as a base of 2. The latter is probably
			 * not necessary according to the original specs, but many
			 * programs that read icons assume it. Especially gdk-pixbuf.
			 */
		    	memclear(&color, sizeof(Win32RGBQuad));
			for (d = palette_count(img[c].palette); d < 1 << img[c].bit_count; d++)
				fwrite(&color, sizeof(Win32RGBQuad), 1, out);
		}

		img[c].image_data = xcalloc(img[c].image_size);

		for (d = 0; d < img[c].height; d++) {
			png_bytep row = img[c].row_datas[img[c].height - d - 1];
			if (img[c].bit_count < 24) {
				uint32_t imod = d * (img[c].image_size/img[c].height) * 8 / img[c].bit_count;
				for (x = 0; x < img[c].width; x++) {
					uint32_t color;
					color = palette_lookup(img[c].palette, row[4*x+0], row[4*x+1], row[4*x+2]);
					simple_setvec(img[c].image_data, x+imod, img[c].bit_count, color);
				}
			} else if (img[c].bit_count == 24) {
				uint32_t irow = d * (img[c].image_size/img[c].height);
				for (x = 0; x < img[c].width; x++) {
					img[c].image_data[3*x+0 + irow] = row[4*x+2];
					img[c].image_data[3*x+1 + irow] = row[4*x+1];
					img[c].image_data[3*x+2 + irow] = row[4*x+0];
				}
			} else if (img[c].bit_count == 32) {
				uint32_t irow = d * (img[c].image_size/img[c].height);
				for (x = 0; x < img[c].width; x++) {
					img[c].image_data[4*x+0 + irow] = row[4*x+2];
					img[c].image_data[4*x+1 + irow] = row[4*x+1];
					img[c].image_data[4*x+2 + irow] = row[4*x+0];
					img[c].image_data[4*x+3 + irow] = row[4*x+3];
				}
			}
		}

		if (fwrite(img[c].image_data, img[c].image_size, 1, out) != 1) {
			warn_errno("cannot write to file");
			goto cleanup;
		}

		for (d = 0; d < img[c].height; d++) {
			png_bytep row = img[c].row_datas[img[c].height - d - 1];

			for (x = 0; x < img[c].width; x += 8) {
				uint8_t mask = 0;
				mask |= (row[4*(x+0)+3] <= alpha_threshold ? 1 << 7 : 0);
				mask |= (row[4*(x+1)+3] <= alpha_threshold ? 1 << 6 : 0);
				mask |= (row[4*(x+2)+3] <= alpha_threshold ? 1 << 5 : 0);
				mask |= (row[4*(x+3)+3] <= alpha_threshold ? 1 << 4 : 0);
				mask |= (row[4*(x+4)+3] <= alpha_threshold ? 1 << 3 : 0);
				mask |= (row[4*(x+5)+3] <= alpha_threshold ? 1 << 2 : 0);
				mask |= (row[4*(x+6)+3] <= alpha_threshold ? 1 << 1 : 0);
				mask |= (row[4*(x+7)+3] <= alpha_threshold ? 1 << 0 : 0);
				fputc(mask, out);
			}

			fpad(out, 0, img[c].mask_size/img[c].height - x/8);
		}

		free(img[c].image_data);
		palette_free(img[c].palette);
		free(img[c].row_datas[0]);
		free(img[c].row_datas);
		png_read_end(img[c].png_ptr, img[c].info_ptr);
		png_destroy_read_struct(&img[c].png_ptr, &img[c].info_ptr, NULL);
		fclose(img[c].in);
		memclear(&img[c], sizeof(*img));
	}

	free(img);
	return true;

cleanup:

	for (c = 0; c < filec; c++) {
		if (img[c].image_data != NULL)
			free(img[c].image_data);
		if (img[c].palette != NULL)
			palette_free(img[c].palette);
		if (img[c].row_datas != NULL && img[c].row_datas[0] != NULL) {
			free(img[c].row_datas[0]);
			free(img[c].row_datas);
		}
		if (img[c].png_ptr != NULL)
			png_destroy_read_struct(&img[c].png_ptr, &img[c].info_ptr, NULL);
		if (img[c].in != NULL)
			fclose(img[c].in);
	}
	free(img);
        if (out) fclose(out);
	return false;
}
