2 * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 FILE_LICENCE ( GPL2_OR_LATER );
24 * Portable anymap format (PNM)
31 #include <ipxe/image.h>
32 #include <ipxe/pixbuf.h>
36 * Extract PNM ASCII value
40 * @ret value Value, or negative error
42 static int pnm_ascii ( struct image *image, struct pnm_context *pnm ) {
43 char buf[ pnm->ascii_len + 1 /* NUL */ ];
49 /* Skip any leading whitespace and comments */
50 for ( ; pnm->offset < image->len ; pnm->offset++ ) {
51 copy_from_user ( &buf[0], image->data, pnm->offset,
57 if ( buf[0] == '#' ) {
59 } else if ( ! isspace ( buf[0] ) ) {
65 /* Fail if no value is present */
66 len = ( image->len - pnm->offset );
68 DBGC ( image, "PNM %s ran out of ASCII data\n", image->name );
72 /* Copy ASCII value to buffer and ensure string is NUL-terminated */
73 if ( len > ( sizeof ( buf ) - 1 /* NUL */ ) )
74 len = ( sizeof ( buf ) - 1 /* NUL */ );
75 copy_from_user ( buf, image->data, pnm->offset, len );
78 /* Parse value and update offset */
79 value = strtoul ( buf, &endp, 0 );
80 pnm->offset += ( endp - buf );
82 /* Check and skip terminating whitespace character, if present */
83 if ( ( pnm->offset != image->len ) && ( *endp != '\0' ) ) {
84 if ( ! isspace ( *endp ) ) {
85 DBGC ( image, "PNM %s invalid ASCII integer\n",
96 * Extract PNM binary value
100 * @ret value Value, or negative error
102 static int pnm_binary ( struct image *image, struct pnm_context *pnm ) {
106 if ( pnm->offset == image->len ) {
107 DBGC ( image, "PNM %s ran out of binary data\n",
113 copy_from_user ( &value, image->data, pnm->offset, sizeof ( value ) );
120 * Scale PNM scalar value
125 * @ret value Scaled value (in range 0-255)
127 static int pnm_scale ( struct image *image, struct pnm_context *pnm,
128 unsigned int value ) {
130 if ( value > pnm->max ) {
131 DBGC ( image, "PNM %s has out-of-range value %d (max %d)\n",
132 image->name, value, pnm->max );
135 return ( ( 255 * value ) / pnm->max );
139 * Convert PNM bitmap composite value to RGB
141 * @v composite Composite value
142 * @v index Pixel index within this composite value
143 * @ret rgb 24-bit RGB value
145 static uint32_t pnm_bitmap ( uint32_t composite, unsigned int index ) {
147 /* Composite value is an 8-bit bitmask */
148 return ( ( ( composite << index ) & 0x80 ) ? 0x000000 : 0xffffff );
152 * Convert PNM greymap composite value to RGB
154 * @v composite Composite value
155 * @v index Pixel index within this composite value
156 * @ret rgb 24-bit RGB value
158 static uint32_t pnm_greymap ( uint32_t composite, unsigned int index __unused ){
160 /* Composite value is an 8-bit greyscale value */
161 return ( ( composite << 16 ) | ( composite << 8 ) | composite );
165 * Convert PNM pixmap composite value to RGB
167 * @v composite Composite value
168 * @v index Pixel index within this composite value
169 * @ret rgb 24-bit RGB value
171 static uint32_t pnm_pixmap ( uint32_t composite, unsigned int index __unused ) {
173 /* Composite value is already an RGB value */
178 * Extract PNM pixel data
182 * @v pixbuf Pixel buffer
183 * @ret rc Return status code
185 static int pnm_data ( struct image *image, struct pnm_context *pnm,
186 struct pixel_buffer *pixbuf ) {
187 struct pnm_type *type = pnm->type;
189 unsigned int xpos = 0;
195 /* Fill pixel buffer */
196 while ( offset < pixbuf->len ) {
198 /* Extract a scaled composite scalar value from the file */
200 for ( i = 0 ; i < type->depth ; i++ ) {
201 scalar = type->scalar ( image, pnm );
204 scalar = pnm_scale ( image, pnm, scalar );
207 composite = ( ( composite << 8 ) | scalar );
210 /* Extract 24-bit RGB values from composite value */
211 for ( i = 0 ; i < type->packing ; i++ ) {
212 if ( offset >= pixbuf->len ) {
213 DBGC ( image, "PNM %s has too many pixels\n",
217 rgb = type->rgb ( composite, i );
218 copy_to_user ( pixbuf->data, offset, &rgb,
220 offset += sizeof ( rgb );
221 if ( ++xpos == pixbuf->width ) {
231 /** PNM image types */
232 static struct pnm_type pnm_types[] = {
260 .scalar = pnm_binary,
267 .scalar = pnm_binary,
274 .scalar = pnm_binary,
280 * Determine PNM image type
283 * @ret type PNM image type, or NULL if not found
285 static struct pnm_type * pnm_type ( struct image *image ) {
286 struct pnm_signature signature;
287 struct pnm_type *type;
290 /* Extract signature */
291 assert ( image->len >= sizeof ( signature ) );
292 copy_from_user ( &signature, image->data, 0, sizeof ( signature ) );
294 /* Check for supported types */
295 for ( i = 0 ; i < ( sizeof ( pnm_types ) /
296 sizeof ( pnm_types[0] ) ) ; i++ ) {
297 type = &pnm_types[i];
298 if ( type->type == signature.type )
305 * Convert PNM image to pixel buffer
308 * @v pixbuf Pixel buffer to fill in
309 * @ret rc Return status code
311 static int pnm_pixbuf ( struct image *image, struct pixel_buffer **pixbuf ) {
312 struct pnm_context pnm;
318 /* Initialise PNM context */
319 pnm.type = pnm_type ( image );
324 pnm.offset = sizeof ( struct pnm_signature );
325 pnm.ascii_len = PNM_ASCII_LEN;
328 if ( ( width = pnm_ascii ( image, &pnm ) ) < 0 ) {
334 if ( ( height = pnm_ascii ( image, &pnm ) ) < 0 ) {
339 /* Extract maximum scalar value, if not predefined */
340 if ( pnm.type->flags & PNM_BITMAP ) {
341 pnm.max = ( ( 1 << pnm.type->packing ) - 1 );
344 if ( ( max = pnm_ascii ( image, &pnm ) ) < 0 ) {
350 if ( pnm.max == 0 ) {
351 DBGC ( image, "PNM %s has invalid maximum value 0\n",
356 DBGC ( image, "PNM %s is type %c width %d height %d max %d\n",
357 image->name, pnm.type->type, width, height, pnm.max );
359 /* Allocate pixel buffer */
360 *pixbuf = alloc_pixbuf ( width, height );
363 goto err_alloc_pixbuf;
366 /* Extract pixel data */
367 if ( ( rc = pnm_data ( image, &pnm, *pixbuf ) ) != 0 )
373 pixbuf_put ( *pixbuf );
386 * @ret rc Return status code
388 static int pnm_probe ( struct image *image ) {
389 struct pnm_signature signature;
392 if ( image->len < sizeof ( signature ) ) {
393 DBGC ( image, "PNM %s is too short\n", image->name );
397 /* Check signature */
398 copy_from_user ( &signature, image->data, 0, sizeof ( signature ) );
399 if ( ! ( ( signature.magic == PNM_MAGIC ) &&
400 ( isdigit ( signature.type ) ) &&
401 ( isspace ( signature.space ) ) ) ) {
402 DBGC ( image, "PNM %s has invalid signature\n", image->name );
405 DBGC ( image, "PNM %s is type %c\n", image->name, signature.type );
410 /** PNM image type */
411 struct image_type pnm_image_type __image_type ( PROBE_NORMAL ) = {
414 .pixbuf = pnm_pixbuf,