1"""Image-handling routines
2
3### Unresolved:
4
5    Following methods are not yet resolved due to my not being sure how the
6    function should be wrapped:
7
8        glCompressedTexImage3D
9        glCompressedTexImage2D
10        glCompressedTexImage1D
11        glCompressedTexSubImage3D
12        glCompressedTexSubImage2D
13        glCompressedTexSubImage1D
14"""
15from OpenGL.raw.GL.VERSION import GL_1_1,GL_1_2, GL_3_0
16from OpenGL import images, arrays, wrapper
17from OpenGL._bytes import bytes,integer_types
18from OpenGL.raw.GL import _types
19import ctypes
20
21def asInt( value ):
22    if isinstance( value, float ):
23        return int(round(value,0))
24    return value
25
26## update the image tables with standard image types...
27images.COMPONENT_COUNTS.update( {
28    GL_1_1.GL_BITMAP : 1, # must be GL_UNSIGNED_BYTE
29
30    GL_1_1.GL_RED : 1,
31    GL_1_1.GL_GREEN : 1,
32    GL_1_1.GL_BLUE : 1,
33    GL_1_1.GL_ALPHA : 1,
34    GL_3_0.GL_RED_INTEGER : 1,
35    GL_3_0.GL_GREEN_INTEGER : 1,
36    GL_3_0.GL_BLUE_INTEGER : 1,
37    GL_3_0.GL_ALPHA_INTEGER : 1,
38    GL_1_1.GL_LUMINANCE : 1,
39    GL_1_1.GL_LUMINANCE_ALPHA : 2,
40    GL_1_1.GL_COLOR_INDEX : 1,
41    GL_1_1.GL_STENCIL_INDEX : 1,
42    GL_1_1.GL_DEPTH_COMPONENT : 1,
43
44    GL_1_1.GL_RGB : 3,
45    GL_1_2.GL_BGR : 3,
46    GL_3_0.GL_RGB16F : 3,
47    GL_3_0.GL_RGB16I : 3,
48    GL_3_0.GL_RGB16UI : 3,
49    GL_3_0.GL_RGB32F : 3,
50    GL_3_0.GL_RGB32I : 3,
51    GL_3_0.GL_RGB32UI : 3,
52    GL_3_0.GL_RGB8I : 3,
53    GL_3_0.GL_RGB8UI : 3,
54    GL_3_0.GL_RGB9_E5 : 3,
55    GL_3_0.GL_RGB_INTEGER : 3,
56
57    GL_1_1.GL_RGBA : 4,
58    GL_1_2.GL_BGRA : 4,
59    GL_3_0.GL_RGBA16F : 4,
60    GL_3_0.GL_RGBA16I : 4,
61    GL_3_0.GL_RGBA16UI : 4,
62    GL_3_0.GL_RGBA32F : 4,
63    GL_3_0.GL_RGBA32I : 4,
64    GL_3_0.GL_RGBA32UI : 4,
65    GL_3_0.GL_RGBA8I : 4,
66    GL_3_0.GL_RGBA8UI : 4,
67    GL_3_0.GL_RGBA_INTEGER : 4,
68} )
69
70images.TYPE_TO_ARRAYTYPE.update( {
71    GL_1_2.GL_UNSIGNED_BYTE_3_3_2 : GL_1_1.GL_UNSIGNED_BYTE,
72    GL_1_2.GL_UNSIGNED_BYTE_2_3_3_REV : GL_1_1.GL_UNSIGNED_BYTE,
73    GL_1_2.GL_UNSIGNED_SHORT_4_4_4_4 : GL_1_1.GL_UNSIGNED_SHORT,
74    GL_1_2.GL_UNSIGNED_SHORT_4_4_4_4_REV : GL_1_1.GL_UNSIGNED_SHORT,
75    GL_1_2.GL_UNSIGNED_SHORT_5_5_5_1 : GL_1_1.GL_UNSIGNED_SHORT,
76    GL_1_2.GL_UNSIGNED_SHORT_1_5_5_5_REV : GL_1_1.GL_UNSIGNED_SHORT,
77    GL_1_2.GL_UNSIGNED_SHORT_5_6_5 : GL_1_1.GL_UNSIGNED_SHORT,
78    GL_1_2.GL_UNSIGNED_SHORT_5_6_5_REV : GL_1_1.GL_UNSIGNED_SHORT,
79    GL_1_2.GL_UNSIGNED_INT_8_8_8_8 : GL_1_1.GL_UNSIGNED_INT,
80    GL_1_2.GL_UNSIGNED_INT_8_8_8_8_REV : GL_1_1.GL_UNSIGNED_INT,
81    GL_1_2.GL_UNSIGNED_INT_10_10_10_2 : GL_1_1.GL_UNSIGNED_INT,
82    GL_1_2.GL_UNSIGNED_INT_2_10_10_10_REV : GL_1_1.GL_UNSIGNED_INT,
83    GL_1_1.GL_UNSIGNED_BYTE : GL_1_1.GL_UNSIGNED_BYTE,
84    GL_1_1.GL_BYTE: GL_1_1.GL_BYTE,
85    GL_1_1.GL_UNSIGNED_SHORT : GL_1_1.GL_UNSIGNED_SHORT,
86    GL_1_1.GL_SHORT :  GL_1_1.GL_SHORT,
87    GL_1_1.GL_UNSIGNED_INT : GL_1_1.GL_UNSIGNED_INT,
88    GL_1_1.GL_INT : GL_1_1.GL_INT,
89    GL_1_1.GL_FLOAT : GL_1_1.GL_FLOAT,
90    GL_1_1.GL_DOUBLE : GL_1_1.GL_DOUBLE,
91    GL_1_1.GL_BITMAP : GL_1_1.GL_UNSIGNED_BYTE,
92} )
93images.TIGHT_PACK_FORMATS.update({
94    GL_1_2.GL_UNSIGNED_BYTE_3_3_2 : 3,
95    GL_1_2.GL_UNSIGNED_BYTE_2_3_3_REV : 3,
96    GL_1_2.GL_UNSIGNED_SHORT_4_4_4_4 : 4,
97    GL_1_2.GL_UNSIGNED_SHORT_4_4_4_4_REV : 4,
98    GL_1_2.GL_UNSIGNED_SHORT_5_5_5_1 : 4,
99    GL_1_2.GL_UNSIGNED_SHORT_1_5_5_5_REV : 4,
100    GL_1_2.GL_UNSIGNED_SHORT_5_6_5 : 3,
101    GL_1_2.GL_UNSIGNED_SHORT_5_6_5_REV : 3,
102    GL_1_2.GL_UNSIGNED_INT_8_8_8_8 : 4,
103    GL_1_2.GL_UNSIGNED_INT_8_8_8_8_REV : 4,
104    GL_1_2.GL_UNSIGNED_INT_10_10_10_2 : 4,
105    GL_1_2.GL_UNSIGNED_INT_2_10_10_10_REV : 4,
106    GL_1_1.GL_BITMAP: 8, # single bits, 8 of them...
107})
108
109images.RANK_PACKINGS.update( {
110    4: [
111        # Note the sgis parameters are skipped here unless you import
112        # the sgis texture4D extension...
113        (GL_1_1.glPixelStorei,GL_1_1.GL_PACK_ALIGNMENT, 1),
114    ],
115    3: [
116        (GL_1_1.glPixelStorei,GL_1_2.GL_PACK_SKIP_IMAGES, 0),
117        (GL_1_1.glPixelStorei,GL_1_2.GL_PACK_IMAGE_HEIGHT, 0),
118        (GL_1_1.glPixelStorei,GL_1_1.GL_PACK_ALIGNMENT, 1),
119    ],
120    2: [
121        (GL_1_1.glPixelStorei,GL_1_1.GL_PACK_ROW_LENGTH, 0),
122        (GL_1_1.glPixelStorei,GL_1_1.GL_PACK_SKIP_ROWS, 0),
123        (GL_1_1.glPixelStorei,GL_1_1.GL_PACK_ALIGNMENT, 1),
124    ],
125    1: [
126        (GL_1_1.glPixelStorei,GL_1_1.GL_PACK_SKIP_PIXELS, 0),
127        (GL_1_1.glPixelStorei,GL_1_1.GL_PACK_ALIGNMENT, 1),
128    ],
129} )
130
131
132__all__ = (
133    'glReadPixels',
134    'glReadPixelsb',
135    'glReadPixelsd',
136    'glReadPixelsf',
137    'glReadPixelsi',
138    'glReadPixelss',
139    'glReadPixelsub',
140    'glReadPixelsui',
141    'glReadPixelsus',
142
143    'glGetTexImage',
144
145    'glDrawPixels',
146    'glDrawPixelsb',
147    'glDrawPixelsf',
148    'glDrawPixelsi',
149    'glDrawPixelss',
150    'glDrawPixelsub',
151    'glDrawPixelsui',
152    'glDrawPixelsus',
153
154
155    'glTexSubImage2D',
156    'glTexSubImage1D',
157    #'glTexSubImage3D',
158
159    'glTexImage1D',
160    'glTexImage2D',
161    #'glTexImage3D',
162
163    'glGetTexImageb',
164    'glGetTexImaged',
165    'glGetTexImagef',
166    'glGetTexImagei',
167    'glGetTexImages',
168    'glGetTexImageub',
169    'glGetTexImageui',
170    'glGetTexImageus',
171    'glTexImage1Db',
172    'glTexImage2Db',
173    #'glTexImage3Db',
174    'glTexSubImage1Db',
175    'glTexSubImage2Db',
176    #'glTexSubImage3Db',
177    'glTexImage1Df',
178    'glTexImage2Df',
179    #'glTexImage3Df',
180    'glTexSubImage1Df',
181    'glTexSubImage2Df',
182    #'glTexSubImage3Df',
183    'glTexImage1Di',
184    'glTexImage2Di',
185    #'glTexImage3Di',
186    'glTexSubImage1Di',
187    'glTexSubImage2Di',
188    #'glTexSubImage3Di',
189    'glTexImage1Ds',
190    'glTexImage2Ds',
191    #'glTexImage3Ds',
192    'glTexSubImage1Ds',
193    'glTexSubImage2Ds',
194    #'glTexSubImage3Ds',
195    'glTexImage1Dub',
196    'glTexImage2Dub',
197    #'glTexImage3Dub',
198    'glTexSubImage1Dub',
199    'glTexSubImage2Dub',
200    #'glTexSubImage3Dub',
201    'glTexImage1Dui',
202    'glTexImage2Dui',
203    #'glTexImage3Dui',
204    'glTexSubImage1Dui',
205    'glTexSubImage2Dui',
206    #'glTexSubImage3Dui',
207    'glTexImage1Dus',
208    'glTexImage2Dus',
209    #'glTexImage3Dus',
210    'glTexSubImage1Dus',
211    'glTexSubImage2Dus',
212    #'glTexSubImage3Dus',
213
214    #'glColorTable',
215    #'glGetColorTable',
216    #'glColorSubTable',
217
218    #'glConvolutionFilter1D',
219    #'glConvolutionFilter2D',
220    #'glGetConvolutionFilter',
221    #'glSeparableFilter2D',
222    #'glGetSeparableFilter',
223
224    #'glGetMinmax',
225)
226
227def _get_texture_level_dims(target,level):
228    """Retrieve texture dims for given level and target"""
229    dims = []
230    dim = _types.GLuint()
231    GL_1_1.glGetTexLevelParameteriv( target, level, GL_1_1.GL_TEXTURE_WIDTH, dim )
232    dims = [dim.value]
233    if target != GL_1_1.GL_TEXTURE_1D:
234        GL_1_1.glGetTexLevelParameteriv( target, level, GL_1_1.GL_TEXTURE_HEIGHT, dim )
235        dims.append( dim.value )
236        if target != GL_1_1.GL_TEXTURE_2D:
237            GL_1_1.glGetTexLevelParameteriv( target, level, GL_1_1.GL_TEXTURE_DEPTH, dim )
238            dims.append( dim.value )
239    return dims
240
241for suffix,type in [
242    ('b',GL_1_1.GL_BYTE),
243    ('d',GL_1_1.GL_DOUBLE),
244    ('f',GL_1_1.GL_FLOAT),
245    ('i',GL_1_1.GL_INT),
246    ('s',GL_1_1.GL_SHORT),
247    ('ub',GL_1_1.GL_UNSIGNED_BYTE),
248    ('ui',GL_1_1.GL_UNSIGNED_INT),
249    ('us',GL_1_1.GL_UNSIGNED_SHORT),
250]:
251    def glReadPixels( x,y,width,height,format,type=type, array=None, outputType=bytes ):
252        """Read specified pixels from the current display buffer
253
254        This typed version returns data in your specified default
255        array data-type format, or in the passed array, which will
256        be converted to the array-type required by the format.
257        """
258        x,y,width,height = asInt(x),asInt(y),asInt(width),asInt(height)
259        arrayType = arrays.GL_CONSTANT_TO_ARRAY_TYPE[ images.TYPE_TO_ARRAYTYPE.get(type,type) ]
260
261        if array is None:
262            array = imageData = images.SetupPixelRead( format, (width,height), type )
263            owned = True
264        else:
265            if isinstance( array, integer_types):
266                imageData = ctypes.c_void_p( array )
267            else:
268                array = arrayType.asArray( array )
269                imageData = arrayType.voidDataPointer( array )
270            owned = False
271        GL_1_1.glReadPixels(
272            x,y,
273            width, height,
274            format,type,
275            imageData
276        )
277        if owned and outputType is bytes:
278            return images.returnFormat( array, type )
279        else:
280            return array
281    globals()["glReadPixels%s"%(suffix,)] = glReadPixels
282    def glGetTexImage( target, level,format,type=type, array=None, outputType=bytes ):
283        """Get a texture-level as an image
284
285        target -- enum constant for the texture engine to be read
286        level -- the mip-map level to read
287        format -- image format to read out the data
288        type -- data-type into which to read the data
289        array -- optional array/offset into which to store the value
290
291        outputType -- default (bytes) provides string output of the
292            results iff OpenGL.UNSIGNED_BYTE_IMAGES_AS_STRING is True
293            and type == GL_UNSIGNED_BYTE.  Any other value will cause
294            output in the default array output format.
295
296        returns the pixel data array in the format defined by the
297        format, type and outputType
298        """
299        arrayType = arrays.GL_CONSTANT_TO_ARRAY_TYPE[ images.TYPE_TO_ARRAYTYPE.get(type,type) ]
300        if array is None:
301            dims = _get_texture_level_dims(target,level)
302            array = imageData = images.SetupPixelRead( format, tuple(dims), type )
303            owned = True
304        else:
305            if isinstance( array, integer_types):
306                imageData = ctypes.c_void_p( array )
307            else:
308                array = arrayType.asArray( array )
309                imageData = arrayType.voidDataPointer( array )
310            owned = False
311        GL_1_1.glGetTexImage(
312            target, level, format, type, imageData
313        )
314        if owned and outputType is bytes:
315            return images.returnFormat( array, type )
316        else:
317            return array
318    globals()["glGetTexImage%s"%(suffix,)] = glGetTexImage
319##	def glGetTexSubImage( target, level,format,type ):
320##		"""Get a texture-level as an image"""
321##		dims = [GL_1_1.glGetTexLevelParameteriv( target, level, GL_1_1.GL_TEXTURE_WIDTH )]
322##		if target != GL_1_1.GL_TEXTURE_1D:
323##			dims.append( GL_1_1.glGetTexLevelParameteriv( target, level, GL_1_1.GL_TEXTURE_HEIGHT ) )
324##			if target != GL_1_1.GL_TEXTURE_2D:
325##				dims.append( GL_1_1.glGetTexLevelParameteriv( target, level, GL_1_2.GL_TEXTURE_DEPTH ) )
326##		array = images.SetupPixelRead( format, tuple(dims), type )
327##		arrayType = arrays.GL_CONSTANT_TO_ARRAY_TYPE[ images.TYPE_TO_ARRAYTYPE.get(type,type) ]
328##		GL_1_1.glGetTexImage(
329##			target, level, format, type, ctypes.c_void_p( arrayType.dataPointer(array))
330##		)
331##		return array
332##	"%s = glGetTexImage"%(suffix)
333    try:
334        del suffix,type
335    except NameError as err:
336        pass
337# Now the real glReadPixels...
338def glReadPixels( x,y,width,height,format,type, array=None, outputType=bytes ):
339    """Read specified pixels from the current display buffer
340
341    x,y,width,height -- location and dimensions of the image to read
342        from the buffer
343    format -- pixel format for the resulting data
344    type -- data-format for the resulting data
345    array -- optional array/offset into which to store the value
346    outputType -- default (bytes) provides string output of the
347        results iff OpenGL.UNSIGNED_BYTE_IMAGES_AS_STRING is True
348        and type == GL_UNSIGNED_BYTE.  Any other value will cause
349        output in the default array output format.
350
351    returns the pixel data array in the format defined by the
352    format, type and outputType
353    """
354    x,y,width,height = asInt(x),asInt(y),asInt(width),asInt(height)
355
356    arrayType = arrays.GL_CONSTANT_TO_ARRAY_TYPE[ images.TYPE_TO_ARRAYTYPE.get(type,type) ]
357    if array is None:
358        array = imageData = images.SetupPixelRead( format, (width,height), type )
359        owned = True
360    else:
361        if isinstance( array, integer_types):
362            imageData = ctypes.c_void_p( array )
363        else:
364            array = arrayType.asArray( array )
365            imageData = arrayType.voidDataPointer( array )
366        owned = False
367
368    GL_1_1.glReadPixels(
369        x,y,width,height,
370        format,type,
371        imageData
372    )
373    if owned and outputType is bytes:
374        return images.returnFormat( array, type )
375    else:
376        return array
377
378def glGetTexImage( target, level,format,type, array=None, outputType=bytes ):
379    """Get a texture-level as an image
380
381    target -- enum constant for the texture engine to be read
382    level -- the mip-map level to read
383    format -- image format to read out the data
384    type -- data-type into which to read the data
385    array -- optional array/offset into which to store the value
386
387    outputType -- default (bytes) provides string output of the
388        results iff OpenGL.UNSIGNED_BYTE_IMAGES_AS_STRING is True
389        and type == GL_UNSIGNED_BYTE.  Any other value will cause
390        output in the default array output format.
391
392    returns the pixel data array in the format defined by the
393    format, type and outputType
394    """
395    arrayType = arrays.GL_CONSTANT_TO_ARRAY_TYPE[ images.TYPE_TO_ARRAYTYPE.get(type,type) ]
396    if array is None:
397        dims = _get_texture_level_dims(target,level)
398        array = imageData = images.SetupPixelRead( format, tuple(dims), type )
399        owned = True
400    else:
401        if isinstance( array, integer_types):
402            imageData = ctypes.c_void_p( array )
403        else:
404            array = arrayType.asArray( array )
405            imageData = arrayType.voidDataPointer( array )
406        owned = False
407    GL_1_1.glGetTexImage(
408        target, level, format, type, imageData
409    )
410    if outputType is bytes:
411        return images.returnFormat( array, type )
412    else:
413        return array
414
415
416INT_DIMENSION_NAMES = [
417    'width','height','depth','x','y','z',
418    'xoffset','yoffset','zoffset',
419    'start', 'count',
420]
421def asWrapper( value ):
422    if not isinstance( value, wrapper.Wrapper ):
423        return wrapper.wrapper( value )
424    return value
425
426def asIntConverter( value, *args ):
427    if isinstance( value, float ):
428        return int(round(value,0))
429    return value
430
431def setDimensionsAsInts( baseOperation ):
432    """Set arguments with names in INT_DIMENSION_NAMES to asInt processing"""
433    baseOperation = asWrapper( baseOperation )
434    argNames = getattr( baseOperation, 'pyConverterNames', baseOperation.argNames )
435    for i,argName in enumerate(argNames):
436        if argName in INT_DIMENSION_NAMES:
437            baseOperation.setPyConverter( argName, asIntConverter )
438    return baseOperation
439
440
441
442class ImageInputConverter( object ):
443    def __init__( self, rank, pixelsName=None, typeName='type' ):
444        self.rank = rank
445        self.typeName = typeName
446        self.pixelsName = pixelsName
447    def finalise( self, wrapper ):
448        """Get our pixel index from the wrapper"""
449        self.typeIndex = wrapper.pyArgIndex( self.typeName )
450        self.pixelsIndex = wrapper.pyArgIndex( self.pixelsName )
451    def __call__( self, arg, baseOperation, pyArgs ):
452        """pyConverter for the pixels argument"""
453        images.setupDefaultTransferMode()
454        images.rankPacking( self.rank )
455        type = pyArgs[ self.typeIndex ]
456        arrayType = arrays.GL_CONSTANT_TO_ARRAY_TYPE[ images.TYPE_TO_ARRAYTYPE[ type ] ]
457        return arrayType.asArray( arg )
458#	def cResolver( self, array ):
459#		return array
460#		return ctypes.c_void_p( arrays.ArrayDatatype.dataPointer( array ) )
461
462class TypedImageInputConverter( ImageInputConverter ):
463    def __init__( self, rank, pixelsName, arrayType, typeName=None ):
464        self.rank = rank
465        self.arrayType = arrayType
466        self.pixelsName = pixelsName
467        self.typeName = typeName
468    def __call__( self, arg, baseOperation, pyArgs ):
469        """The pyConverter for the pixels"""
470        images.setupDefaultTransferMode()
471        images.rankPacking( self.rank )
472        return self.arrayType.asArray( arg )
473    def finalise( self, wrapper ):
474        """Get our pixel index from the wrapper"""
475        self.pixelsIndex = wrapper.pyArgIndex( self.pixelsName )
476    def width( self, pyArgs, index, wrappedOperation ):
477        """Extract the width from the pixels argument"""
478        return self.arrayType.dimensions( pyArgs[self.pixelsIndex] )[0]
479    def height( self, pyArgs, index, wrappedOperation ):
480        """Extract the height from the pixels argument"""
481        return self.arrayType.dimensions( pyArgs[self.pixelsIndex] )[1]
482    def depth( self, pyArgs, index, wrappedOperation ):
483        """Extract the depth from the pixels argument"""
484        return self.arrayType.dimensions( pyArgs[self.pixelsIndex] )[2]
485    def type( self, pyArgs, index, wrappedOperation ):
486        """Provide the item-type argument from our stored value
487
488        This is used for pre-bound processing where we want to provide
489        the type by implication...
490        """
491        return self.typeName
492
493class CompressedImageConverter( object ):
494    def finalise( self, wrapper ):
495        """Get our pixel index from the wrapper"""
496        self.dataIndex = wrapper.pyArgIndex( 'data' )
497    def __call__( self, pyArgs, index, wrappedOperation ):
498        """Create a data-size measurement for our image"""
499        arg = pyArgs[ self.dataIndex ]
500        return arrays.ArrayType.arrayByteCount( arg )
501
502
503
504DIMENSION_NAMES = (
505    'width','height','depth'
506)
507PIXEL_NAMES = (
508    'pixels', 'row', 'column',
509)
510DATA_SIZE_NAMES = (
511    'imageSize',
512)
513
514def setImageInput(
515    baseOperation, arrayType=None, dimNames=DIMENSION_NAMES,
516    pixelName="pixels", typeName=None
517):
518    """Determine how to convert "pixels" into an image-compatible argument"""
519    baseOperation = asWrapper( baseOperation )
520    # rank is the count of width,height,depth arguments...
521    rank = len([
522        # rank is the number of dims we want, not the number we give...
523        argName for argName in baseOperation.argNames
524        if argName in dimNames
525    ]) + 1
526    if arrayType:
527        converter = TypedImageInputConverter( rank, pixelName, arrayType, typeName=typeName )
528        for i,argName in enumerate(baseOperation.argNames):
529            if argName in dimNames:
530                baseOperation.setPyConverter( argName )
531                baseOperation.setCConverter( argName, getattr(converter,argName) )
532            elif argName == 'type' and typeName is not None:
533                baseOperation.setPyConverter( argName )
534                baseOperation.setCConverter( argName, converter.type )
535    else:
536        converter = ImageInputConverter( rank, pixelsName=pixelName, typeName=typeName or 'type' )
537    for argName in baseOperation.argNames:
538        if argName in DATA_SIZE_NAMES:
539            baseOperation.setPyConverter( argName )
540            baseOperation.setCConverter( argName, converter.imageDataSize )
541    baseOperation.setPyConverter(
542        pixelName, converter,
543    )
544#	baseOperation.setCResolver(
545#		pixelName, converter.cResolver
546#	)
547    return baseOperation
548
549glDrawPixels = setDimensionsAsInts(
550    setImageInput(
551        GL_1_1.glDrawPixels
552    )
553)
554glTexSubImage2D = setDimensionsAsInts(
555    setImageInput(
556        GL_1_1.glTexSubImage2D
557    )
558)
559glTexSubImage1D = setDimensionsAsInts(
560    setImageInput(
561        GL_1_1.glTexSubImage1D
562    )
563)
564glTexImage2D = setDimensionsAsInts(
565    setImageInput(
566        GL_1_1.glTexImage2D
567    )
568)
569glTexImage1D = setDimensionsAsInts(
570    setImageInput(
571        GL_1_1.glTexImage1D
572    )
573)
574
575def typedImageFunction( suffix, arrayConstant,  baseFunction ):
576    """Produce a typed version of the given image function"""
577    functionName = baseFunction.__name__
578    functionName = '%(functionName)s%(suffix)s'%locals()
579    if baseFunction:
580        arrayType = arrays.GL_CONSTANT_TO_ARRAY_TYPE[ arrayConstant ]
581        function = setDimensionsAsInts(
582            setImageInput(
583                baseFunction,
584                arrayType,
585                typeName = arrayConstant,
586            )
587        )
588        return functionName, function
589    else:
590        return functionName, baseFunction
591
592def _setDataSize( baseFunction, argument='imageSize' ):
593    """Set the data-size value to come from the data field"""
594    if baseFunction:
595        converter = CompressedImageConverter()
596        return asWrapper( baseFunction ).setPyConverter(
597            argument
598        ).setCConverter( argument, converter )
599    else:
600        return baseFunction
601
602def compressedImageFunction( baseFunction ):
603    """Set the imageSize and dimensions-as-ints converters for baseFunction"""
604    if baseFunction:
605        return setDimensionsAsInts(
606            _setDataSize(
607                baseFunction, argument='imageSize'
608            )
609        )
610    else:
611        return baseFunction
612
613for suffix,arrayConstant in [
614    ('b', GL_1_1.GL_BYTE),
615    ('f', GL_1_1.GL_FLOAT),
616    ('i', GL_1_1.GL_INT),
617    ('s', GL_1_1.GL_SHORT),
618    ('ub', GL_1_1.GL_UNSIGNED_BYTE),
619    ('ui', GL_1_1.GL_UNSIGNED_INT),
620    ('us', GL_1_1.GL_UNSIGNED_SHORT),
621]:
622    for functionName in (
623        'glTexImage1D','glTexImage2D',
624        'glTexSubImage1D','glTexSubImage2D',
625        'glDrawPixels',
626        #'glTexSubImage3D','glTexImage3D', # extension/1.2 standard
627    ):
628        functionName, function = typedImageFunction(
629            suffix, arrayConstant, getattr(GL_1_1,functionName),
630        )
631        globals()[functionName] = function
632        try:
633            del function, functionName
634        except NameError as err:
635            pass
636    try:
637        del suffix,arrayConstant
638    except NameError as err:
639        pass
640