mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-10-30 23:47:27 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			567 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			567 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * The Python Imaging Library.
 | |
|  * $Id$
 | |
|  *
 | |
|  * code to pack raw data
 | |
|  *
 | |
|  * history:
 | |
|  * 1996-04-30 fl   Created
 | |
|  * 1996-05-12 fl   Published a few RGB packers
 | |
|  * 1996-11-01 fl   More RGB packers (Tk booster stuff)
 | |
|  * 1996-12-30 fl   Added P;1, P;2 and P;4 packers
 | |
|  * 1997-06-02 fl   Added F (F;32NF) packer
 | |
|  * 1997-08-28 fl   Added 1 as L packer
 | |
|  * 1998-02-08 fl   Added I packer
 | |
|  * 1998-03-09 fl   Added mode field, RGBA/RGBX as RGB packers
 | |
|  * 1998-07-01 fl   Added YCbCr support
 | |
|  * 1998-07-12 fl   Added I 16 packer
 | |
|  * 1999-02-03 fl   Added BGR packers
 | |
|  * 2003-09-26 fl   Added LA/PA packers
 | |
|  * 2006-06-22 fl   Added CMYK;I packer
 | |
|  *
 | |
|  * Copyright (c) 1997-2006 by Secret Labs AB.
 | |
|  * Copyright (c) 1996-1997 by Fredrik Lundh.
 | |
|  *
 | |
|  * See the README file for information on usage and redistribution.
 | |
|  */
 | |
| 
 | |
| 
 | |
| #include "Imaging.h"
 | |
| 
 | |
| #define	R 0
 | |
| #define	G 1
 | |
| #define	B 2
 | |
| #define	X 3
 | |
| #define	A 3
 | |
| 
 | |
| #define	C 0
 | |
| #define	M 1
 | |
| #define	Y 2
 | |
| #define	K 3
 | |
| 
 | |
| /* byte swapping macros */
 | |
| 
 | |
| #define C16N\
 | |
|         (out[0]=tmp[0], out[1]=tmp[1]);
 | |
| #define C16S\
 | |
|         (out[1]=tmp[0], out[0]=tmp[1]);
 | |
| #define C32N\
 | |
|         (out[0]=tmp[0], out[1]=tmp[1], out[2]=tmp[2], out[3]=tmp[3]);
 | |
| #define C32S\
 | |
|         (out[3]=tmp[0], out[2]=tmp[1], out[1]=tmp[2], out[0]=tmp[3]);
 | |
| #define C64N\
 | |
|         (out[0]=tmp[0], out[1]=tmp[1], out[2]=tmp[2], out[3]=tmp[3],\
 | |
|          out[4]=tmp[4], out[5]=tmp[5], out[6]=tmp[6], out[7]=tmp[7]);
 | |
| #define C64S\
 | |
|         (out[7]=tmp[0], out[6]=tmp[1], out[5]=tmp[2], out[4]=tmp[3],\
 | |
|          out[3]=tmp[4], out[2]=tmp[5], out[1]=tmp[6], out[0]=tmp[7]);
 | |
| 
 | |
| #ifdef WORDS_BIGENDIAN
 | |
| #define C16B C16N
 | |
| #define C16L C16S
 | |
| #define C32B C32N
 | |
| #define C32L C32S
 | |
| #define C64B C64N
 | |
| #define C64L C64S
 | |
| #else
 | |
| #define C16B C16S
 | |
| #define C16L C16N
 | |
| #define C32B C32S
 | |
| #define C32L C32N
 | |
| #define C64B C64S
 | |
| #define C64L C64N
 | |
| #endif
 | |
| 
 | |
| static void
 | |
| pack1(UINT8* out, const UINT8* in, int pixels)
 | |
| {
 | |
|     int i, m, b;
 | |
|     /* bilevel (black is 0) */
 | |
|     b = 0; m = 128;
 | |
|     for (i = 0; i < pixels; i++) {
 | |
| 	if (in[i] != 0)
 | |
| 	    b |= m;
 | |
| 	m >>= 1;
 | |
| 	if (m == 0) {
 | |
| 	    *out++ = b;
 | |
| 	    b = 0; m = 128;
 | |
| 	}
 | |
|     }
 | |
|     if (m != 128)
 | |
| 	*out++ = b;
 | |
| }
 | |
| 
 | |
| static void
 | |
| pack1I(UINT8* out, const UINT8* in, int pixels)
 | |
| {
 | |
|     int i, m, b;
 | |
|     /* bilevel (black is 1) */
 | |
|     b = 0; m = 128;
 | |
|     for (i = 0; i < pixels; i++) {
 | |
| 	if (in[i] == 0)
 | |
| 	    b |= m;
 | |
| 	m >>= 1;
 | |
| 	if (m == 0) {
 | |
| 	    *out++ = b;
 | |
| 	    b = 0; m = 128;
 | |
| 	}
 | |
|     }
 | |
|     if (m != 128)
 | |
| 	*out++ = b;
 | |
| }
 | |
| 
 | |
| static void
 | |
| pack1R(UINT8* out, const UINT8* in, int pixels)
 | |
| {
 | |
|     int i, m, b;
 | |
|     /* bilevel, lsb first (black is 0) */
 | |
|     b = 0; m = 1;
 | |
|     for (i = 0; i < pixels; i++) {
 | |
| 	if (in[i] != 0)
 | |
| 	    b |= m;
 | |
| 	m <<= 1;
 | |
| 	if (m == 256){
 | |
| 	    *out++ = b;
 | |
| 	    b = 0; m = 1;
 | |
| 	}
 | |
|     }
 | |
|     if (m != 1)
 | |
| 	*out++ = b;
 | |
| }
 | |
| 
 | |
| static void
 | |
| pack1IR(UINT8* out, const UINT8* in, int pixels)
 | |
| {
 | |
|     int i, m, b;
 | |
|     /* bilevel, lsb first (black is 1) */
 | |
|     b = 0; m = 1;
 | |
|     for (i = 0; i < pixels; i++) {
 | |
| 	if (in[i] == 0)
 | |
| 	    b |= m;
 | |
| 	m <<= 1;
 | |
| 	if (m == 256){
 | |
| 	    *out++ = b;
 | |
| 	    b = 0; m = 1;
 | |
| 	}
 | |
|     }
 | |
|     if (m != 1)
 | |
| 	*out++ = b;
 | |
| }
 | |
| 
 | |
| static void
 | |
| pack1L(UINT8* out, const UINT8* in, int pixels)
 | |
| {
 | |
|     int i;
 | |
|     /* bilevel, stored as bytes */
 | |
|     for (i = 0; i < pixels; i++)
 | |
| 	out[i] = (in[i] != 0) ? 255 : 0;
 | |
| }
 | |
| 
 | |
| static void
 | |
| packP4(UINT8* out, const UINT8* in, int pixels)
 | |
| {
 | |
|     while (pixels >= 2) {
 | |
| 	*out++ = (in[0] << 4) |
 | |
| 		 (in[1] & 15);
 | |
| 	in += 2; pixels -= 2;
 | |
|     }
 | |
| 
 | |
|     if (pixels)
 | |
| 	out[0] = (in[0] << 4);
 | |
| }
 | |
| 
 | |
| static void
 | |
| packP2(UINT8* out, const UINT8* in, int pixels)
 | |
| {
 | |
|     while (pixels >= 4) {
 | |
| 	*out++ = (in[0] << 6) |
 | |
| 		 ((in[1] & 3) << 4) |
 | |
| 		 ((in[2] & 3) << 2) |
 | |
| 		 (in[3] & 3);
 | |
| 	in += 4; pixels -= 4;
 | |
|     }
 | |
| 
 | |
|     switch (pixels) {
 | |
|     case 3:
 | |
| 	out[0] = (in[0] << 6) |
 | |
| 		 ((in[1] & 3) << 4) |
 | |
| 		 ((in[2] & 3) << 2);
 | |
| 	break;
 | |
|     case 2:
 | |
| 	out[0] = (in[0] << 6) |
 | |
| 		 ((in[1] & 3) << 4);
 | |
|     case 1:
 | |
| 	out[0] = (in[0] << 6);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| packLA(UINT8* out, const UINT8* in, int pixels)
 | |
| {
 | |
|     int i;
 | |
|     /* LA, pixel interleaved */
 | |
|     for (i = 0; i < pixels; i++) {
 | |
| 	out[0] = in[R];
 | |
| 	out[1] = in[A];
 | |
| 	out += 2; in += 4;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| packLAL(UINT8* out, const UINT8* in, int pixels)
 | |
| {
 | |
|     int i;
 | |
|     /* LA, line interleaved */
 | |
|     for (i = 0; i < pixels; i++) {
 | |
| 	out[i] = in[R];
 | |
| 	out[i+pixels] = in[A];
 | |
| 	in += 4;
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| ImagingPackRGB(UINT8* out, const UINT8* in, int pixels)
 | |
| {
 | |
|     int i;
 | |
|     /* RGB triplets */
 | |
|     for (i = 0; i < pixels; i++) {
 | |
| 	out[0] = in[R];
 | |
| 	out[1] = in[G];
 | |
| 	out[2] = in[B];
 | |
| 	out += 3; in += 4;
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| ImagingPackXRGB(UINT8* out, const UINT8* in, int pixels)
 | |
| {
 | |
|     int i;
 | |
|     /* XRGB, triplets with left padding */
 | |
|     for (i = 0; i < pixels; i++) {
 | |
| 	out[0] = 0;
 | |
| 	out[1] = in[R];
 | |
| 	out[2] = in[G];
 | |
| 	out[3] = in[B];
 | |
| 	out += 4; in += 4;
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| ImagingPackBGR(UINT8* out, const UINT8* in, int pixels)
 | |
| {
 | |
|     int i;
 | |
|     /* RGB, reversed bytes */
 | |
|     for (i = 0; i < pixels; i++) {
 | |
| 	out[0] = in[B];
 | |
| 	out[1] = in[G];
 | |
| 	out[2] = in[R];
 | |
| 	out += 3; in += 4;
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| ImagingPackBGRX(UINT8* out, const UINT8* in, int pixels)
 | |
| {
 | |
|     int i;
 | |
|     /* BGRX, reversed bytes with right padding */
 | |
|     for (i = 0; i < pixels; i++) {
 | |
| 	out[0] = in[B];
 | |
| 	out[1] = in[G];
 | |
| 	out[2] = in[R];
 | |
| 	out[3] = 0;
 | |
| 	out += 4; in += 4;
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| ImagingPackXBGR(UINT8* out, const UINT8* in, int pixels)
 | |
| {
 | |
|     int i;
 | |
|     /* XBGR, reversed bytes with left padding */
 | |
|     for (i = 0; i < pixels; i++) {
 | |
| 	out[0] = 0;
 | |
| 	out[1] = in[B];
 | |
| 	out[2] = in[G];
 | |
| 	out[3] = in[R];
 | |
| 	out += 4; in += 4;
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| ImagingPackBGRA(UINT8* out, const UINT8* in, int pixels)
 | |
| {
 | |
|     int i;
 | |
|     /* BGRX, reversed bytes with right padding */
 | |
|     for (i = 0; i < pixels; i++) {
 | |
| 	out[0] = in[B];
 | |
| 	out[1] = in[G];
 | |
| 	out[2] = in[R];
 | |
| 	out[3] = in[A];
 | |
| 	out += 4; in += 4;
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| ImagingPackABGR(UINT8* out, const UINT8* in, int pixels)
 | |
| {
 | |
|     int i;
 | |
|     /* XBGR, reversed bytes with left padding */
 | |
|     for (i = 0; i < pixels; i++) {
 | |
| 	out[0] = in[A];
 | |
| 	out[1] = in[B];
 | |
| 	out[2] = in[G];
 | |
| 	out[3] = in[R];
 | |
| 	out += 4; in += 4;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| packRGBL(UINT8* out, const UINT8* in, int pixels)
 | |
| {
 | |
|     int i;
 | |
|     /* RGB, line interleaved */
 | |
|     for (i = 0; i < pixels; i++) {
 | |
| 	out[i] = in[R];
 | |
| 	out[i+pixels] = in[G];
 | |
| 	out[i+pixels+pixels] = in[B];
 | |
| 	in += 4;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| packRGBXL(UINT8* out, const UINT8* in, int pixels)
 | |
| {
 | |
|     int i;
 | |
|     /* RGBX, line interleaved */
 | |
|     for (i = 0; i < pixels; i++) {
 | |
| 	out[i] = in[R];
 | |
| 	out[i+pixels] = in[G];
 | |
| 	out[i+pixels+pixels] = in[B];
 | |
| 	out[i+pixels+pixels+pixels] = in[X];
 | |
| 	in += 4;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| packI16B(UINT8* out, const UINT8* in_, int pixels)
 | |
| {
 | |
|     int i;
 | |
|     INT32* in = (INT32*) in_;
 | |
|     UINT16 tmp_;
 | |
|     UINT8* tmp = (UINT8*) &tmp_;
 | |
|     for (i = 0; i < pixels; i++) {
 | |
|         if (in[0] <= 0)
 | |
|             tmp_ = 0;
 | |
|         else if (in[0] > 65535)
 | |
|             tmp_ = 65535;
 | |
|         else
 | |
|             tmp_ = in[0];
 | |
|         C16B;
 | |
| 	out += 2; in++;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| packI32S(UINT8* out, const UINT8* in, int pixels)
 | |
| {
 | |
|     int i;
 | |
|     UINT8* tmp = (UINT8*) in;
 | |
|     for (i = 0; i < pixels; i++) {
 | |
|         C32L;
 | |
| 	out += 4; tmp += 4;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| copy1(UINT8* out, const UINT8* in, int pixels)
 | |
| {
 | |
|     /* L, P */
 | |
|     memcpy(out, in, pixels);
 | |
| }
 | |
| 
 | |
| static void
 | |
| copy2(UINT8* out, const UINT8* in, int pixels)
 | |
| {
 | |
|     /* I;16, etc */
 | |
|     memcpy(out, in, pixels*2);
 | |
| }
 | |
| 
 | |
| static void
 | |
| copy3(UINT8* out, const UINT8* in, int pixels)
 | |
| {
 | |
|     /* BGR;24, etc */
 | |
|     memcpy(out, in, pixels*3);
 | |
| }
 | |
| 
 | |
| static void
 | |
| copy4(UINT8* out, const UINT8* in, int pixels)
 | |
| {
 | |
|     /* RGBA, CMYK quadruples */
 | |
|     memcpy(out, in, 4*pixels);
 | |
| }
 | |
| 
 | |
| static void
 | |
| copy4I(UINT8* out, const UINT8* in, int pixels)
 | |
| {
 | |
|     /* RGBA, CMYK quadruples, inverted */
 | |
|     int i;
 | |
|     for (i = 0; i < pixels*4; i++)
 | |
| 	out[i] = ~in[i];
 | |
| }
 | |
| 
 | |
| static void
 | |
| band0(UINT8* out, const UINT8* in, int pixels)
 | |
| {
 | |
|     int i;
 | |
|     for (i = 0; i < pixels; i++, in += 4)
 | |
| 	out[i] = in[0];
 | |
| }
 | |
| 
 | |
| static void
 | |
| band1(UINT8* out, const UINT8* in, int pixels)
 | |
| {
 | |
|     int i;
 | |
|     for (i = 0; i < pixels; i++, in += 4)
 | |
| 	out[i] = in[1];
 | |
| }
 | |
| 
 | |
| static void
 | |
| band2(UINT8* out, const UINT8* in, int pixels)
 | |
| {
 | |
|     int i;
 | |
|     for (i = 0; i < pixels; i++, in += 4)
 | |
| 	out[i] = in[2];
 | |
| }
 | |
| 
 | |
| static void
 | |
| band3(UINT8* out, const UINT8* in, int pixels)
 | |
| {
 | |
|     int i;
 | |
|     for (i = 0; i < pixels; i++, in += 4)
 | |
| 	out[i] = in[3];
 | |
| }
 | |
| 
 | |
| static struct {
 | |
|     const char* mode;
 | |
|     const char* rawmode;
 | |
|     int bits;
 | |
|     ImagingShuffler pack;
 | |
| } packers[] = {
 | |
| 
 | |
|     /* bilevel */
 | |
|     {"1",	"1",   		1,	pack1},
 | |
|     {"1",	"1;I",   	1,	pack1I},
 | |
|     {"1",	"1;R",   	1,	pack1R},
 | |
|     {"1",	"1;IR",   	1,	pack1IR},
 | |
|     {"1",	"L",		8,	pack1L},
 | |
| 
 | |
|     /* greyscale */
 | |
|     {"L",	"L",   		8,	copy1},
 | |
| 
 | |
|     /* greyscale w. alpha */
 | |
|     {"LA",	"LA",  		16,	packLA},
 | |
|     {"LA",	"LA;L",		16,	packLAL},
 | |
| 
 | |
|     /* palette */
 | |
|     {"P",	"P;1",		1,	pack1},
 | |
|     {"P",	"P;2",		2,	packP2},
 | |
|     {"P",	"P;4",		4,	packP4},
 | |
|     {"P",	"P",		8,	copy1},
 | |
| 
 | |
|     /* palette w. alpha */
 | |
|     {"PA",	"PA",  		16,	packLA},
 | |
|     {"PA",	"PA;L",		16,	packLAL},
 | |
| 
 | |
|     /* true colour */
 | |
|     {"RGB",	"RGB",		24,	ImagingPackRGB},
 | |
|     {"RGB",	"RGBX",		32,	copy4},
 | |
|     {"RGB",	"XRGB",		32,	ImagingPackXRGB},
 | |
|     {"RGB",	"BGR",		24,	ImagingPackBGR},
 | |
|     {"RGB",	"BGRX",		32,	ImagingPackBGRX},
 | |
|     {"RGB",	"XBGR",		32,	ImagingPackXBGR},
 | |
|     {"RGB",	"RGB;L",	24,	packRGBL},
 | |
|     {"RGB",   	"R",            8,      band0},
 | |
|     {"RGB",   	"G",            8,      band1},
 | |
|     {"RGB",   	"B",            8,      band2},
 | |
| 
 | |
|     /* true colour w. alpha */
 | |
|     {"RGBA",	"RGBA",		32,	copy4},
 | |
|     {"RGBA",	"RGBA;L",	32,	packRGBXL},
 | |
|     {"RGBA",	"RGB",		24,	ImagingPackRGB},
 | |
|     {"RGBA",	"BGR",		24,	ImagingPackBGR},
 | |
|     {"RGBA",	"BGRA",		32,	ImagingPackBGRA},
 | |
|     {"RGBA",	"ABGR",		32,	ImagingPackABGR},
 | |
|     {"RGBA",   	"R",            8,      band0},
 | |
|     {"RGBA",   	"G",            8,      band1},
 | |
|     {"RGBA",   	"B",            8,      band2},
 | |
|     {"RGBA",   	"A",            8,      band3},
 | |
| 
 | |
|     /* true colour w. padding */
 | |
|     {"RGBX",	"RGBX",		32,	copy4},
 | |
|     {"RGBX",	"RGBX;L",	32,	packRGBXL},
 | |
|     {"RGBX",	"RGB",		32,	ImagingPackRGB},
 | |
|     {"RGBX",	"BGR",		32,	ImagingPackBGR},
 | |
|     {"RGBX",	"BGRX",		32,	ImagingPackBGRX},
 | |
|     {"RGBX",	"XBGR",		32,	ImagingPackXBGR},
 | |
|     {"RGBX",   	"R",            8,      band0},
 | |
|     {"RGBX",   	"G",            8,      band1},
 | |
|     {"RGBX",   	"B",            8,      band2},
 | |
|     {"RGBX",   	"X",            8,      band3},
 | |
| 
 | |
|     /* colour separation */
 | |
|     {"CMYK",	"CMYK",		32,	copy4},
 | |
|     {"CMYK",	"CMYK;I",	32,	copy4I},
 | |
|     {"CMYK",	"CMYK;L",	32,	packRGBXL},
 | |
|     {"CMYK",   	"C",            8,      band0},
 | |
|     {"CMYK",   	"M",            8,      band1},
 | |
|     {"CMYK",   	"Y",            8,      band2},
 | |
|     {"CMYK",   	"K",            8,      band3},
 | |
| 
 | |
|     /* video (YCbCr) */
 | |
|     {"YCbCr",	"YCbCr",	24,	ImagingPackRGB},
 | |
|     {"YCbCr",	"YCbCr;L",	24,	packRGBL},
 | |
|     {"YCbCr",	"YCbCrX",	32,	copy4},
 | |
|     {"YCbCr",	"YCbCrK",	32,	copy4},
 | |
|     {"YCbCr",  	"Y",            8,      band0},
 | |
|     {"YCbCr",  	"Cb",           8,      band1},
 | |
|     {"YCbCr",  	"Cr",           8,      band2},
 | |
| 
 | |
|     /* integer */
 | |
|     {"I", 	"I",		32,	copy4},
 | |
|     {"I", 	"I;16B",	16,	packI16B},
 | |
|     {"I", 	"I;32S",	32,	packI32S},
 | |
|     {"I", 	"I;32NS",	32,	copy4},
 | |
| 
 | |
|     /* floating point */
 | |
|     {"F",	"F",		32,	copy4},
 | |
|     {"F", 	"F;32F",	32,	packI32S},
 | |
|     {"F",	"F;32NF",	32,	copy4},
 | |
| 
 | |
|     /* storage modes */
 | |
|     {"I;16", 	"I;16",		16,	copy2},
 | |
|     {"I;16B", 	"I;16B",	16,	copy2},
 | |
|     {"I;16L", 	"I;16L",	16,	copy2},
 | |
|     {"BGR;15", 	"BGR;15",	16,	copy2},
 | |
|     {"BGR;16", 	"BGR;16",	16,	copy2},
 | |
|     {"BGR;24", 	"BGR;24",	24,	copy3},
 | |
| 
 | |
|     {NULL} /* sentinel */
 | |
| };
 | |
| 
 | |
| 
 | |
| ImagingShuffler
 | |
| ImagingFindPacker(const char* mode, const char* rawmode, int* bits_out)
 | |
| {
 | |
|     int i;
 | |
| 
 | |
|     /* find a suitable pixel packer */
 | |
|     for (i = 0; packers[i].rawmode; i++)
 | |
| 	if (strcmp(packers[i].mode, mode) == 0 &&
 | |
|             strcmp(packers[i].rawmode, rawmode) == 0) {
 | |
| 	    if (bits_out)
 | |
| 		*bits_out = packers[i].bits;
 | |
| 	    return packers[i].pack;
 | |
| 	}
 | |
|     return NULL;
 | |
| }
 |