mirror of
				https://git.code.sf.net/p/libpng/code.git
				synced 2025-07-10 18:04:09 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			149 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			149 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
 | |
| /* pngwtran.c - transforms the data in a row for PNG writers
 | |
|  *
 | |
|  * Last changed in libpng 1.6.17 [(PENDING RELEASE)]
 | |
|  * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson
 | |
|  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
 | |
|  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
 | |
|  *
 | |
|  * This code is released under the libpng license.
 | |
|  * For conditions of distribution and use, see the disclaimer
 | |
|  * and license in png.h
 | |
|  */
 | |
| 
 | |
| #include "pngpriv.h"
 | |
| #define PNG_SRC_FILE PNG_SRC_FILE_pngwtran
 | |
| 
 | |
| #ifdef PNG_WRITE_PACK_SUPPORTED
 | |
| /* Pack pixels into bytes. */
 | |
| static void
 | |
| png_do_write_pack(png_transformp *transform, png_transform_controlp tc)
 | |
| {
 | |
|    png_alloc_size_t rowbytes = PNG_TC_ROWBYTES(*tc);
 | |
|    png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | |
|    png_const_bytep ep = png_upcast(png_const_bytep, tc->sp) + rowbytes;
 | |
|    png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | |
| 
 | |
|    png_debug(1, "in png_do_pack");
 | |
| 
 | |
| #  define png_ptr tc->png_ptr
 | |
| 
 | |
|    switch ((*transform)->args)
 | |
|    {
 | |
|       case 1:
 | |
|       {
 | |
|          unsigned int mask = 0x80, v = 0;
 | |
| 
 | |
|          while (sp < ep)
 | |
|          {
 | |
|             if (*sp++ != 0)
 | |
|                v |= mask;
 | |
| 
 | |
|             mask >>= 1;
 | |
| 
 | |
|             if (mask == 0)
 | |
|             {
 | |
|                mask = 0x80;
 | |
|                *dp++ = PNG_BYTE(v);
 | |
|                v = 0;
 | |
|             }
 | |
|          }
 | |
| 
 | |
|          if (mask != 0x80)
 | |
|             *dp++ = PNG_BYTE(v);
 | |
|          break;
 | |
|       }
 | |
| 
 | |
|       case 2:
 | |
|       {
 | |
|          unsigned int shift = 8, v = 0;
 | |
| 
 | |
|          while (sp < ep)
 | |
|          {
 | |
|             shift -= 2;
 | |
|             v |= (*sp++ & 0x3) << shift;
 | |
| 
 | |
|             if (shift == 0)
 | |
|             {
 | |
|                shift = 8;
 | |
|                *dp++ = PNG_BYTE(v);
 | |
|                v = 0;
 | |
|             }
 | |
|          }
 | |
| 
 | |
|          if (shift != 8)
 | |
|             *dp++ = PNG_BYTE(v);
 | |
|          break;
 | |
|       }
 | |
| 
 | |
|       case 4:
 | |
|       {
 | |
|          unsigned int shift = 8, v = 0;
 | |
| 
 | |
|          while (sp < ep)
 | |
|          {
 | |
|             shift -= 4;
 | |
|             v |= ((*sp++ & 0xf) << shift);
 | |
| 
 | |
|             if (shift == 0)
 | |
|             {
 | |
|                shift = 8;
 | |
|                *dp++ = PNG_BYTE(v);
 | |
|                v = 0;
 | |
|             }
 | |
|          }
 | |
| 
 | |
|          if (shift != 8)
 | |
|             *dp++ = PNG_BYTE(v);
 | |
|          break;
 | |
|       }
 | |
| 
 | |
|       default:
 | |
|          impossible("bit depth");
 | |
|    }
 | |
| 
 | |
|    if ((tc->format & PNG_FORMAT_FLAG_COLORMAP) == 0 &&
 | |
|        --(tc->range) == 0)
 | |
|       tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_RANGE);
 | |
| 
 | |
|    tc->bit_depth = (*transform)->args;
 | |
|    tc->sp = tc->dp;
 | |
| #  undef png_ptr
 | |
| }
 | |
| 
 | |
| void /* PRIVATE */
 | |
| png_init_write_pack(png_transformp *transform, png_transform_controlp tc)
 | |
| {
 | |
| #  define png_ptr tc->png_ptr
 | |
|    debug(tc->init);
 | |
| #  undef png_ptr
 | |
| 
 | |
|    /* The init routine is called *forward* so the transform control we get has
 | |
|     * the required bit depth and the transform routine will increase it to 8
 | |
|     * bits per channel.  The code doesn't really care how many channels there
 | |
|     * are, but the only way to get a channel depth of less than 8 is to have
 | |
|     * just one channel.
 | |
|     */
 | |
|    if (tc->bit_depth < 8) /* else no packing/unpacking */
 | |
|    {
 | |
|       if (tc->init == PNG_TC_INIT_FINAL)
 | |
|       {
 | |
|          (*transform)->fn = png_do_write_pack;
 | |
|          /* Record this for the backwards run: */
 | |
|          (*transform)->args = tc->bit_depth & 0xf;
 | |
|       }
 | |
| 
 | |
|       if ((tc->format & PNG_FORMAT_FLAG_COLORMAP) == 0)
 | |
|       {
 | |
|          tc->range++;
 | |
|          tc->format |= PNG_FORMAT_FLAG_RANGE; /* forwards: backwards cancels */
 | |
|       }
 | |
| 
 | |
|       tc->bit_depth = 8;
 | |
|    }
 | |
| 
 | |
|    else /* the transform is not applicable */
 | |
|       (*transform)->fn = NULL;
 | |
| }
 | |
| #endif /* WRITE_PACK */
 | 
