mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-10-31 07:57:27 +03:00 
			
		
		
		
	Preserve auxiliary channels during CMS transform.
This commit is contained in:
		
							parent
							
								
									fa56b3d255
								
							
						
					
					
						commit
						4a1ad8986f
					
				
							
								
								
									
										101
									
								
								_imagingcms.c
									
									
									
									
									
								
							
							
						
						
									
										101
									
								
								_imagingcms.c
									
									
									
									
									
								
							|  | @ -291,6 +291,97 @@ findLCMStype(char* PILmode) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #define Cms_Min(a, b) ((a) < (b) ? (a) : (b)) | ||||||
|  | 
 | ||||||
|  | static int | ||||||
|  | pyCMSgetAuxChannelChannel (cmsUInt32Number format, int auxChannelNdx) | ||||||
|  | { | ||||||
|  |     int numColors = T_CHANNELS(format); | ||||||
|  |     int numExtras = T_EXTRA(format); | ||||||
|  | 
 | ||||||
|  |     if (T_SWAPFIRST(format) && T_DOSWAP(format)) { | ||||||
|  |         // reverse order, before anything but last extra is shifted last
 | ||||||
|  |         if (auxChannelNdx == numExtras - 1) | ||||||
|  |             return numColors + numExtras - 1; | ||||||
|  |         else | ||||||
|  |             return numExtras - 2 - auxChannelNdx; | ||||||
|  |     } | ||||||
|  |     else if (T_SWAPFIRST(format)) { | ||||||
|  |         // in order, after color channels, but last extra is shifted to first
 | ||||||
|  |         if (auxChannelNdx == numExtras - 1) | ||||||
|  |             return 0; | ||||||
|  |         else | ||||||
|  |             return numColors + 1 + auxChannelNdx; | ||||||
|  |     } | ||||||
|  |     else if (T_DOSWAP(format)) { | ||||||
|  |         // reverse order, before anything
 | ||||||
|  |         return numExtras - 1 - auxChannelNdx; | ||||||
|  |     } | ||||||
|  |     else { | ||||||
|  |         // in order, after color channels
 | ||||||
|  |         return numColors + auxChannelNdx; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void | ||||||
|  | pyCMScopyAux (cmsHTRANSFORM hTransform, Imaging imDst, const Imaging imSrc) | ||||||
|  | { | ||||||
|  |     cmsUInt32Number dstLCMSFormat; | ||||||
|  |     cmsUInt32Number srcLCMSFormat; | ||||||
|  |     int numSrcExtras; | ||||||
|  |     int numDstExtras; | ||||||
|  |     int numExtras; | ||||||
|  |     int ySize; | ||||||
|  |     int xSize; | ||||||
|  |     int channelSize; | ||||||
|  |     int srcChunkSize; | ||||||
|  |     int dstChunkSize; | ||||||
|  |     int e; | ||||||
|  | 
 | ||||||
|  |     // trivially copied
 | ||||||
|  |     if (imDst == imSrc) | ||||||
|  |         return; | ||||||
|  | 
 | ||||||
|  |     dstLCMSFormat = cmsGetTransformOutputFormat(hTransform); | ||||||
|  |     srcLCMSFormat = cmsGetTransformInputFormat(hTransform); | ||||||
|  | 
 | ||||||
|  |     // currently, all Pillow formats are chunky formats, but check it anyway
 | ||||||
|  |     if (T_PLANAR(dstLCMSFormat) || T_PLANAR(srcLCMSFormat)) | ||||||
|  |         return; | ||||||
|  | 
 | ||||||
|  |     // copy only if channel format is identical, except OPTIMIZED is ignored as it
 | ||||||
|  |     // does not affect the aux channel
 | ||||||
|  |     if (T_FLOAT(dstLCMSFormat) != T_FLOAT(srcLCMSFormat) | ||||||
|  |         || T_FLAVOR(dstLCMSFormat) != T_FLAVOR(srcLCMSFormat) | ||||||
|  |         || T_ENDIAN16(dstLCMSFormat) != T_ENDIAN16(srcLCMSFormat) | ||||||
|  |         || T_BYTES(dstLCMSFormat) != T_BYTES(srcLCMSFormat)) | ||||||
|  |       return; | ||||||
|  | 
 | ||||||
|  |     numSrcExtras = T_EXTRA(srcLCMSFormat); | ||||||
|  |     numDstExtras = T_EXTRA(dstLCMSFormat); | ||||||
|  |     numExtras = Cms_Min(numSrcExtras, numDstExtras); | ||||||
|  |     ySize = Cms_Min(imSrc->ysize, imDst->ysize); | ||||||
|  |     xSize = Cms_Min(imSrc->xsize, imDst->xsize); | ||||||
|  |     channelSize = T_BYTES(dstLCMSFormat); | ||||||
|  |     srcChunkSize = (T_CHANNELS(srcLCMSFormat) + T_EXTRA(srcLCMSFormat)) * channelSize; | ||||||
|  |     dstChunkSize = (T_CHANNELS(dstLCMSFormat) + T_EXTRA(dstLCMSFormat)) * channelSize; | ||||||
|  | 
 | ||||||
|  |     for (e = 0; e < numExtras; ++e) { | ||||||
|  |         int y; | ||||||
|  |         int dstChannel = pyCMSgetAuxChannelChannel(dstLCMSFormat, e); | ||||||
|  |         int srcChannel = pyCMSgetAuxChannelChannel(srcLCMSFormat, e); | ||||||
|  | 
 | ||||||
|  |         for (y = 0; y < ySize; y++) { | ||||||
|  |             int x; | ||||||
|  |             char* pDstExtras = imDst->image[y] + dstChannel * channelSize; | ||||||
|  |             const char* pSrcExtras = imSrc->image[y] + srcChannel * channelSize; | ||||||
|  | 
 | ||||||
|  |             for (x = 0; x < xSize; x++) | ||||||
|  |                 memcpy(pDstExtras + x * dstChunkSize, pSrcExtras + x * srcChunkSize, channelSize); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static int | static int | ||||||
| pyCMSdoTransform(Imaging im, Imaging imOut, cmsHTRANSFORM hTransform) | pyCMSdoTransform(Imaging im, Imaging imOut, cmsHTRANSFORM hTransform) | ||||||
| { | { | ||||||
|  | @ -301,9 +392,19 @@ pyCMSdoTransform(Imaging im, Imaging imOut, cmsHTRANSFORM hTransform) | ||||||
| 
 | 
 | ||||||
|     Py_BEGIN_ALLOW_THREADS |     Py_BEGIN_ALLOW_THREADS | ||||||
| 
 | 
 | ||||||
|  |     // transform color channels only
 | ||||||
|     for (i = 0; i < im->ysize; i++) |     for (i = 0; i < im->ysize; i++) | ||||||
|         cmsDoTransform(hTransform, im->image[i], imOut->image[i], im->xsize); |         cmsDoTransform(hTransform, im->image[i], imOut->image[i], im->xsize); | ||||||
| 
 | 
 | ||||||
|  |     // lcms by default does nothing to the auxiliary channels leaving those
 | ||||||
|  |     // unchanged. To do "the right thing" here, i.e. maintain identical results
 | ||||||
|  |     // with and without inPlace, we replicate those channels to the output.
 | ||||||
|  |     //
 | ||||||
|  |     // As of lcms 2.8, a new cmsFLAGS_COPY_ALPHA flag is introduced which would
 | ||||||
|  |     // do the same thing automagically. Unfortunately, lcms2.8 is not yet widely
 | ||||||
|  |     // enough available on all platforms, so we polyfill it here for now.
 | ||||||
|  |     pyCMScopyAux(hTransform, imOut, im); | ||||||
|  | 
 | ||||||
|     Py_END_ALLOW_THREADS |     Py_END_ALLOW_THREADS | ||||||
| 
 | 
 | ||||||
|     return 0; |     return 0; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user