src/lib/png.c
changeset 100 aee9d0b12fe9
parent 97 84952fa708d4
child 108 b81d2fcfa446
equal deleted inserted replaced
99:fa21919d105f 100:aee9d0b12fe9
   272 {
   272 {
   273     return data + (row * header->row_bytes) + (col * header->col_bytes);
   273     return data + (row * header->row_bytes) + (col * header->col_bytes);
   274 }
   274 }
   275 
   275 
   276 /**
   276 /**
   277  * Fill in a clipped region of \a width_px pixels at the given row segment
       
   278  */
       
   279 static inline void tile_row_fill_clip (const struct pt_png_header *header, png_byte *row, size_t width_px)
       
   280 {
       
   281     // XXX: use a configureable background color, or full transparency?
       
   282     memset(row, /* 0xd7 */ 0x00, width_px * header->col_bytes);
       
   283 }
       
   284 
       
   285 /**
       
   286  * Write raw tile image data, directly from the cache
   277  * Write raw tile image data, directly from the cache
   287  */
   278  */
   288 static int pt_png_encode_direct (struct pt_png_img *img, const struct pt_png_header *header, const uint8_t *data, const struct pt_tile_info *ti)
   279 static int pt_png_encode_direct (struct pt_png_img *img, const struct pt_png_header *header, const uint8_t *data, const struct pt_tile_info *ti)
   289 {
   280 {
   290     for (size_t row = ti->y; row < ti->y + ti->height; row++)
   281     for (size_t row = ti->y; row < ti->y + ti->height; row++)
   291         // write data directly
   282         // write data directly
   292         // missing const...
   283         // missing const...
   293         png_write_row(img->png, (const png_bytep) tile_row_col(header, data, row, ti->x));
   284         png_write_row(img->png, (const png_bytep) tile_row_col(header, data, row, ti->x));
   294 
   285 
   295     return 0;
   286     return 0;
       
   287 }
       
   288 
       
   289 /**
       
   290  * Fill in a clipped region of \a width_px pixels at the given row segment
       
   291  */
       
   292 static inline void tile_row_fill_clip (const struct pt_png_header *header, png_byte *row, size_t width_px)
       
   293 {
       
   294     // XXX: use a configureable background color, or full transparency?
       
   295     memset(row, /* 0xd7 */ 0x00, width_px * header->col_bytes);
   296 }
   296 }
   297 
   297 
   298 /**
   298 /**
   299  * Write clipped tile image data (a tile that goes over the edge of the actual image) by aligning the data from the cache as needed
   299  * Write clipped tile image data (a tile that goes over the edge of the actual image) by aligning the data from the cache as needed
   300  */
   300  */
   343 
   343 
   344     // ok
   344     // ok
   345     return 0;
   345     return 0;
   346 }
   346 }
   347 
   347 
   348 static inline size_t scale_by_zoom_factor (size_t value, int z)
       
   349 {
       
   350     if (z > 0)
       
   351         return value << z;
       
   352 
       
   353     else if (z < 0)
       
   354         return value >> -z;
       
   355 
       
   356     else
       
   357         return value;
       
   358 }
       
   359 
       
   360 #define ADD_AVG(l, r) (l) = ((l) + (r)) / 2
       
   361 
       
   362 static inline int png_pixel_data (png_color *out, const struct pt_png_header *header, const uint8_t *data, size_t row, size_t col)
       
   363 {
       
   364     if (header->color_type == PNG_COLOR_TYPE_PALETTE) {
       
   365         // palette entry number
       
   366         int p;
       
   367 
       
   368         if (header->bit_depth == 8)
       
   369             p = *((uint8_t *) tile_row_col(header, data, row, col));
       
   370         else
       
   371             return -1;
       
   372 
       
   373         if (p >= header->num_palette)
       
   374             return -1;
       
   375         
       
   376         // reference data from palette
       
   377         *out = header->palette[p];
       
   378 
       
   379         return 0;
       
   380 
       
   381     } else {
       
   382         return -1;
       
   383     }
       
   384 }
       
   385 
       
   386 /**
   348 /**
   387  * Write unscaled tile data
   349  * Write unscaled tile data
   388  */
   350  */
   389 static int pt_png_encode_unzoomed (struct pt_png_img *img, const struct pt_png_header *header, const uint8_t *data, const struct pt_tile_info *ti)
   351 static int pt_png_encode_unzoomed (struct pt_png_img *img, const struct pt_png_header *header, const uint8_t *data, const struct pt_tile_info *ti)
   390 {
   352 {
   417     
   379     
   418     return err;
   380     return err;
   419 }
   381 }
   420 
   382 
   421 /**
   383 /**
       
   384  * Manipulate powers of two
       
   385  */
       
   386 static inline size_t scale_by_zoom_factor (size_t value, int z)
       
   387 {
       
   388     if (z > 0)
       
   389         return value << z;
       
   390 
       
   391     else if (z < 0)
       
   392         return value >> -z;
       
   393 
       
   394     else
       
   395         return value;
       
   396 }
       
   397 
       
   398 #define ADD_AVG(l, r) (l) = ((l) + (r)) / 2
       
   399 
       
   400 /**
       
   401  * Converts a pixel's data into a png_color
       
   402  */
       
   403 static inline void png_pixel_data (png_color *out, const struct pt_png_header *header, const uint8_t *data, size_t row, size_t col)
       
   404 {
       
   405     if (header->color_type == PNG_COLOR_TYPE_PALETTE) {
       
   406         // palette entry number
       
   407         int p;
       
   408 
       
   409         if (header->bit_depth == 8)
       
   410             p = *((uint8_t *) tile_row_col(header, data, row, col));
       
   411         else
       
   412             // unknown
       
   413             return;
       
   414 
       
   415         if (p >= header->num_palette)
       
   416             return;
       
   417         
       
   418         // reference data from palette
       
   419         *out = header->palette[p];
       
   420 
       
   421     } else {
       
   422         // unknown
       
   423     }
       
   424 }
       
   425 
       
   426 /**
   422  * Write scaled tile data
   427  * Write scaled tile data
   423  */
   428  */
   424 static int pt_png_encode_zoomed (struct pt_png_img *img, const struct pt_png_header *header, const uint8_t *data, const struct pt_tile_info *ti)
   429 static int pt_png_encode_zoomed (struct pt_png_img *img, const struct pt_png_header *header, const uint8_t *data, const struct pt_tile_info *ti)
   425 {
   430 {
   426     // size of the image data in px
   431     // size of the image data in px
   439     // size of an output row in bytes (RGB)
   444     // size of an output row in bytes (RGB)
   440     size_t row_bytes = row_width * 3;
   445     size_t row_bytes = row_width * 3;
   441 
   446 
   442     // buffer to hold output rows
   447     // buffer to hold output rows
   443     uint8_t *row_buf;
   448     uint8_t *row_buf;
       
   449                 
       
   450     
       
   451     png_color c = { };
   444     
   452     
   445     // only supports zooming out...
   453     // only supports zooming out...
   446     if (ti->zoom >= 0)
   454     if (ti->zoom >= 0)
   447         RETURN_ERROR(PT_ERR_TILE_ZOOM);
   455         RETURN_ERROR(PT_ERR_TILE_ZOOM);
   448 
   456 
   469         
   477         
   470         // ...each out row includes pixel_size in rows
   478         // ...each out row includes pixel_size in rows
   471         for (size_t in_row = in_row_offset; in_row < in_row_offset + pixel_size && in_row < header->height; in_row++) {
   479         for (size_t in_row = in_row_offset; in_row < in_row_offset + pixel_size && in_row < header->height; in_row++) {
   472             // and includes each input pixel
   480             // and includes each input pixel
   473             for (size_t in_col = ti->x; in_col < ti->x + data_width && in_col < header->width; in_col++) {
   481             for (size_t in_col = ti->x; in_col < ti->x + data_width && in_col < header->width; in_col++) {
   474                 png_color c;
       
   475 
   482 
   476                 // ...for this output pixel
   483                 // ...for this output pixel
   477                 size_t out_col = scale_by_zoom_factor(in_col - ti->x, ti->zoom);
   484                 size_t out_col = scale_by_zoom_factor(in_col - ti->x, ti->zoom);
   478                 
   485                 
   479                 // get pixel RGB data
   486                 // get pixel RGB data
   480                 if (png_pixel_data(&c, header, data, in_row, in_col))
   487                 png_pixel_data(&c, header, data, in_row, in_col);
   481                     return -1;
       
   482                 
   488                 
   483                 // average the RGB data        
   489                 // average the RGB data        
   484                 ADD_AVG(row_buf[out_col * pixel_bytes + 0], c.red);
   490                 ADD_AVG(row_buf[out_col * pixel_bytes + 0], c.red);
   485                 ADD_AVG(row_buf[out_col * pixel_bytes + 1], c.green);
   491                 ADD_AVG(row_buf[out_col * pixel_bytes + 1], c.green);
   486                 ADD_AVG(row_buf[out_col * pixel_bytes + 2], c.blue);
   492                 ADD_AVG(row_buf[out_col * pixel_bytes + 2], c.blue);
   566 
   572 
   567     return err;
   573     return err;
   568 }
   574 }
   569 
   575 
   570 
   576 
   571 
       
   572 
       
   573 
       
   574 
       
   575 
       
   576 
       
   577 
       
   578 
       
   579 void pt_png_release_read (struct pt_png_img *img)
   577 void pt_png_release_read (struct pt_png_img *img)
   580 {
   578 {
   581     png_destroy_read_struct(&img->png, &img->info, NULL);
   579     png_destroy_read_struct(&img->png, &img->info, NULL);
   582     
   580     
   583     // close possible filehandle
   581     // close possible filehandle