6 #include <gdk-pixbuf/gdk-pixbuf.h>
7 #include <libxml/HTMLparser.h>
8 #include <libxml/SAX2.h>
9 #include <libxml/uri.h>
10 #include <libxml/xmlstring.h>
12 static inline unsigned int get_word(const unsigned char *buffer
)
16 ret
|= buffer
[0] << 0;
17 ret
|= buffer
[1] << 8;
22 static int get_content(struct chmFile
*file
, const char *path
,
23 unsigned char **buffer
)
25 struct chmUnitInfo ui
;
27 if (chm_resolve_object(file
, path
, &ui
) == CHM_RESOLVE_FAILURE
)
29 if ((*buffer
= malloc(ui
.length
)) == NULL
)
31 if (chm_retrieve_object(file
, &ui
, *buffer
, 0, ui
.length
) !=
41 static char *get_home_path(struct chmFile
*file
)
43 unsigned char *buffer
;
44 unsigned int current
, type
, len
, total
;
47 if ((total
= get_content(file
, "/#SYSTEM", &buffer
)) == 0)
49 for (current
= 4; current
< total
; current
+= 4 + len
)
51 type
= get_word(buffer
+ current
);
52 len
= get_word(buffer
+ current
+ 2);
55 if (current
+ 4 + len
<= total
&& (path
= malloc(len
+ 1)))
58 memcpy(path
+ 1, buffer
+ current
+ 4, len
);
68 GdkPixbuf
*get_image_from_data(unsigned char *buffer
, int length
)
73 input
= g_memory_input_stream_new_from_data(buffer
, length
, NULL
);
74 image
= gdk_pixbuf_new_from_stream(input
, NULL
, NULL
);
75 g_input_stream_close(input
, NULL
, NULL
);
80 static inline int round_div(const int x
, const int y
)
82 return (x
+ y
/ 2) / y
;
85 GdkPixbuf
*scale_image(GdkPixbuf
*original
, int size
)
90 width
= gdk_pixbuf_get_width(original
);
91 height
= gdk_pixbuf_get_height(original
);
94 width
= round_div(width
* size
, height
);
95 type
= height
<= size
? GDK_INTERP_TILES
: GDK_INTERP_HYPER
;
100 height
= round_div(height
* size
, width
);
101 type
= width
<= size
? GDK_INTERP_TILES
: GDK_INTERP_HYPER
;
105 return gdk_pixbuf_scale_simple(original
, width
, height
, type
);
108 static const double lambda
= 0.993;
112 struct chmFile
*file
;
116 const xmlChar
*current
;
119 static int get_content_length(struct chmFile
*file
, const char *path
)
121 struct chmUnitInfo ui
;
123 if (chm_resolve_object(file
, path
, &ui
) == CHM_RESOLVE_FAILURE
)
129 static void startelem(struct inner_file
*fp
, const xmlChar
*name
,
130 const xmlChar
**atts
)
135 if (!xmlStrcasecmp(name
, (const xmlChar
*)"img"))
139 if (!xmlStrcasecmp(*atts
, (const xmlChar
*)"src"))
141 uri
= xmlBuildURI(atts
[1], fp
->current
);
142 size
= get_content_length(fp
->file
, (const char *)uri
) *
160 static char *parse_home(struct chmFile
*file
, unsigned char *buffer
,
163 struct inner_file fp
= { .file
= file
, .path
= NULL
, .size
= 0, .w
= 1.0,
164 .current
= xmlURIEscapeStr((const xmlChar
*)current
, NULL
) };
165 htmlSAXHandler sax
= { .startElement
= (startElementSAXFunc
)startelem
};
167 htmlSAXParseDoc(buffer
, NULL
, &sax
, &fp
);
169 free((void *)fp
.current
);
170 return (char *)fp
.path
;
173 int main(const int argc
, const char *argv
[])
175 struct chmFile
*file
;
176 char *homepath
, *imagepath
= NULL
;
177 unsigned char *buffer
;
178 int buffer_length
, size
;
179 GdkPixbuf
*image
, *output
;
181 if (argc
!= 4 || (size
= atoi(argv
[3])) <= 0)
185 if ((file
= chm_open(argv
[1])) == NULL
)
187 if ((homepath
= get_home_path(file
)) == NULL
)
189 if ((buffer_length
= get_content(file
, homepath
, &buffer
)) == 0)
191 if ((image
= get_image_from_data(buffer
, buffer_length
)) == NULL
)
193 if ((imagepath
= parse_home(file
, buffer
, homepath
)) == NULL
)
196 if ((buffer_length
= get_content(file
, imagepath
, &buffer
)) == 0)
198 if ((image
= get_image_from_data(buffer
, buffer_length
)) == NULL
)
202 output
= scale_image(image
, size
);
203 gdk_pixbuf_save(output
, argv
[2], "png", NULL
, "compression", "9", NULL
);
206 g_object_unref(image
);
207 g_object_unref(output
);