2 /* pngtrans.c - transforms the data in a row (used by both readers and writers)
4 * libpng 1.0.10 - March 30, 2001
5 * For conditions of distribution and use, see copyright notice in png.h
6 * Copyright (c) 1998-2001 Glenn Randers-Pehrson
7 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
8 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
14 #if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
15 /* turn on BGR-to-RGB mapping */
17 png_set_bgr(png_structp png_ptr
)
19 png_debug(1, "in png_set_bgr\n");
20 png_ptr
->transformations
|= PNG_BGR
;
24 #if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
25 /* turn on 16 bit byte swapping */
27 png_set_swap(png_structp png_ptr
)
29 png_debug(1, "in png_set_swap\n");
30 if (png_ptr
->bit_depth
== 16)
31 png_ptr
->transformations
|= PNG_SWAP_BYTES
;
35 #if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
36 /* turn on pixel packing */
38 png_set_packing(png_structp png_ptr
)
40 png_debug(1, "in png_set_packing\n");
41 if (png_ptr
->bit_depth
< 8)
43 png_ptr
->transformations
|= PNG_PACK
;
44 png_ptr
->usr_bit_depth
= 8;
49 #if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED)
50 /* turn on packed pixel swapping */
52 png_set_packswap(png_structp png_ptr
)
54 png_debug(1, "in png_set_packswap\n");
55 if (png_ptr
->bit_depth
< 8)
56 png_ptr
->transformations
|= PNG_PACKSWAP
;
60 #if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED)
62 png_set_shift(png_structp png_ptr
, png_color_8p true_bits
)
64 png_debug(1, "in png_set_shift\n");
65 png_ptr
->transformations
|= PNG_SHIFT
;
66 png_ptr
->shift
= *true_bits
;
70 #if defined(PNG_READ_INTERLACING_SUPPORTED) || \
71 defined(PNG_WRITE_INTERLACING_SUPPORTED)
73 png_set_interlace_handling(png_structp png_ptr
)
75 png_debug(1, "in png_set_interlace handling\n");
76 if (png_ptr
->interlaced
)
78 png_ptr
->transformations
|= PNG_INTERLACE
;
86 #if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED)
87 /* Add a filler byte on read, or remove a filler or alpha byte on write.
88 * The filler type has changed in v0.95 to allow future 2-byte fillers
89 * for 48-bit input data, as well as to avoid problems with some compilers
90 * that don't like bytes as parameters.
93 png_set_filler(png_structp png_ptr
, png_uint_32 filler
, int filler_loc
)
95 png_debug(1, "in png_set_filler\n");
96 png_ptr
->transformations
|= PNG_FILLER
;
97 png_ptr
->filler
= (png_byte
)filler
;
98 if (filler_loc
== PNG_FILLER_AFTER
)
99 png_ptr
->flags
|= PNG_FLAG_FILLER_AFTER
;
101 png_ptr
->flags
&= ~PNG_FLAG_FILLER_AFTER
;
103 /* This should probably go in the "do_filler" routine.
104 * I attempted to do that in libpng-1.0.1a but that caused problems
105 * so I restored it in libpng-1.0.2a
108 if (png_ptr
->color_type
== PNG_COLOR_TYPE_RGB
)
110 png_ptr
->usr_channels
= 4;
113 /* Also I added this in libpng-1.0.2a (what happens when we expand
114 * a less-than-8-bit grayscale to GA? */
116 if (png_ptr
->color_type
== PNG_COLOR_TYPE_GRAY
&& png_ptr
->bit_depth
>= 8)
118 png_ptr
->usr_channels
= 2;
123 #if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \
124 defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
126 png_set_swap_alpha(png_structp png_ptr
)
128 png_debug(1, "in png_set_swap_alpha\n");
129 png_ptr
->transformations
|= PNG_SWAP_ALPHA
;
133 #if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \
134 defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
136 png_set_invert_alpha(png_structp png_ptr
)
138 png_debug(1, "in png_set_invert_alpha\n");
139 png_ptr
->transformations
|= PNG_INVERT_ALPHA
;
143 #if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED)
145 png_set_invert_mono(png_structp png_ptr
)
147 png_debug(1, "in png_set_invert_mono\n");
148 png_ptr
->transformations
|= PNG_INVERT_MONO
;
151 /* invert monochrome grayscale data */
153 png_do_invert(png_row_infop row_info
, png_bytep row
)
155 png_debug(1, "in png_do_invert\n");
156 if (row_info
->bit_depth
== 1 &&
157 #if defined(PNG_USELESS_TESTS_SUPPORTED)
158 row
!= NULL
&& row_info
!= NULL
&&
160 row_info
->color_type
== PNG_COLOR_TYPE_GRAY
)
164 png_uint_32 istop
= row_info
->rowbytes
;
166 for (i
= 0; i
< istop
; i
++)
168 *rp
= (png_byte
)(~(*rp
));
175 #if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
176 /* swaps byte order on 16 bit depth images */
178 png_do_swap(png_row_infop row_info
, png_bytep row
)
180 png_debug(1, "in png_do_swap\n");
182 #if defined(PNG_USELESS_TESTS_SUPPORTED)
183 row
!= NULL
&& row_info
!= NULL
&&
185 row_info
->bit_depth
== 16)
189 png_uint_32 istop
= row_info
->width
* row_info
->channels
;
191 for (i
= 0; i
< istop
; i
++, rp
+= 2)
201 #if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED)
202 static png_byte onebppswaptable
[256] = {
203 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
204 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
205 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
206 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
207 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
208 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
209 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
210 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
211 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
212 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
213 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
214 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
215 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
216 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
217 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
218 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
219 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
220 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
221 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
222 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
223 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
224 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
225 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
226 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
227 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
228 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
229 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
230 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
231 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
232 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
233 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
234 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
237 static png_byte twobppswaptable
[256] = {
238 0x00, 0x40, 0x80, 0xC0, 0x10, 0x50, 0x90, 0xD0,
239 0x20, 0x60, 0xA0, 0xE0, 0x30, 0x70, 0xB0, 0xF0,
240 0x04, 0x44, 0x84, 0xC4, 0x14, 0x54, 0x94, 0xD4,
241 0x24, 0x64, 0xA4, 0xE4, 0x34, 0x74, 0xB4, 0xF4,
242 0x08, 0x48, 0x88, 0xC8, 0x18, 0x58, 0x98, 0xD8,
243 0x28, 0x68, 0xA8, 0xE8, 0x38, 0x78, 0xB8, 0xF8,
244 0x0C, 0x4C, 0x8C, 0xCC, 0x1C, 0x5C, 0x9C, 0xDC,
245 0x2C, 0x6C, 0xAC, 0xEC, 0x3C, 0x7C, 0xBC, 0xFC,
246 0x01, 0x41, 0x81, 0xC1, 0x11, 0x51, 0x91, 0xD1,
247 0x21, 0x61, 0xA1, 0xE1, 0x31, 0x71, 0xB1, 0xF1,
248 0x05, 0x45, 0x85, 0xC5, 0x15, 0x55, 0x95, 0xD5,
249 0x25, 0x65, 0xA5, 0xE5, 0x35, 0x75, 0xB5, 0xF5,
250 0x09, 0x49, 0x89, 0xC9, 0x19, 0x59, 0x99, 0xD9,
251 0x29, 0x69, 0xA9, 0xE9, 0x39, 0x79, 0xB9, 0xF9,
252 0x0D, 0x4D, 0x8D, 0xCD, 0x1D, 0x5D, 0x9D, 0xDD,
253 0x2D, 0x6D, 0xAD, 0xED, 0x3D, 0x7D, 0xBD, 0xFD,
254 0x02, 0x42, 0x82, 0xC2, 0x12, 0x52, 0x92, 0xD2,
255 0x22, 0x62, 0xA2, 0xE2, 0x32, 0x72, 0xB2, 0xF2,
256 0x06, 0x46, 0x86, 0xC6, 0x16, 0x56, 0x96, 0xD6,
257 0x26, 0x66, 0xA6, 0xE6, 0x36, 0x76, 0xB6, 0xF6,
258 0x0A, 0x4A, 0x8A, 0xCA, 0x1A, 0x5A, 0x9A, 0xDA,
259 0x2A, 0x6A, 0xAA, 0xEA, 0x3A, 0x7A, 0xBA, 0xFA,
260 0x0E, 0x4E, 0x8E, 0xCE, 0x1E, 0x5E, 0x9E, 0xDE,
261 0x2E, 0x6E, 0xAE, 0xEE, 0x3E, 0x7E, 0xBE, 0xFE,
262 0x03, 0x43, 0x83, 0xC3, 0x13, 0x53, 0x93, 0xD3,
263 0x23, 0x63, 0xA3, 0xE3, 0x33, 0x73, 0xB3, 0xF3,
264 0x07, 0x47, 0x87, 0xC7, 0x17, 0x57, 0x97, 0xD7,
265 0x27, 0x67, 0xA7, 0xE7, 0x37, 0x77, 0xB7, 0xF7,
266 0x0B, 0x4B, 0x8B, 0xCB, 0x1B, 0x5B, 0x9B, 0xDB,
267 0x2B, 0x6B, 0xAB, 0xEB, 0x3B, 0x7B, 0xBB, 0xFB,
268 0x0F, 0x4F, 0x8F, 0xCF, 0x1F, 0x5F, 0x9F, 0xDF,
269 0x2F, 0x6F, 0xAF, 0xEF, 0x3F, 0x7F, 0xBF, 0xFF
272 static png_byte fourbppswaptable
[256] = {
273 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
274 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0,
275 0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71,
276 0x81, 0x91, 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1,
277 0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72,
278 0x82, 0x92, 0xA2, 0xB2, 0xC2, 0xD2, 0xE2, 0xF2,
279 0x03, 0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73,
280 0x83, 0x93, 0xA3, 0xB3, 0xC3, 0xD3, 0xE3, 0xF3,
281 0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74,
282 0x84, 0x94, 0xA4, 0xB4, 0xC4, 0xD4, 0xE4, 0xF4,
283 0x05, 0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75,
284 0x85, 0x95, 0xA5, 0xB5, 0xC5, 0xD5, 0xE5, 0xF5,
285 0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76,
286 0x86, 0x96, 0xA6, 0xB6, 0xC6, 0xD6, 0xE6, 0xF6,
287 0x07, 0x17, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77,
288 0x87, 0x97, 0xA7, 0xB7, 0xC7, 0xD7, 0xE7, 0xF7,
289 0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78,
290 0x88, 0x98, 0xA8, 0xB8, 0xC8, 0xD8, 0xE8, 0xF8,
291 0x09, 0x19, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79,
292 0x89, 0x99, 0xA9, 0xB9, 0xC9, 0xD9, 0xE9, 0xF9,
293 0x0A, 0x1A, 0x2A, 0x3A, 0x4A, 0x5A, 0x6A, 0x7A,
294 0x8A, 0x9A, 0xAA, 0xBA, 0xCA, 0xDA, 0xEA, 0xFA,
295 0x0B, 0x1B, 0x2B, 0x3B, 0x4B, 0x5B, 0x6B, 0x7B,
296 0x8B, 0x9B, 0xAB, 0xBB, 0xCB, 0xDB, 0xEB, 0xFB,
297 0x0C, 0x1C, 0x2C, 0x3C, 0x4C, 0x5C, 0x6C, 0x7C,
298 0x8C, 0x9C, 0xAC, 0xBC, 0xCC, 0xDC, 0xEC, 0xFC,
299 0x0D, 0x1D, 0x2D, 0x3D, 0x4D, 0x5D, 0x6D, 0x7D,
300 0x8D, 0x9D, 0xAD, 0xBD, 0xCD, 0xDD, 0xED, 0xFD,
301 0x0E, 0x1E, 0x2E, 0x3E, 0x4E, 0x5E, 0x6E, 0x7E,
302 0x8E, 0x9E, 0xAE, 0xBE, 0xCE, 0xDE, 0xEE, 0xFE,
303 0x0F, 0x1F, 0x2F, 0x3F, 0x4F, 0x5F, 0x6F, 0x7F,
304 0x8F, 0x9F, 0xAF, 0xBF, 0xCF, 0xDF, 0xEF, 0xFF
307 /* swaps pixel packing order within bytes */
309 png_do_packswap(png_row_infop row_info
, png_bytep row
)
311 png_debug(1, "in png_do_packswap\n");
313 #if defined(PNG_USELESS_TESTS_SUPPORTED)
314 row
!= NULL
&& row_info
!= NULL
&&
316 row_info
->bit_depth
< 8)
318 png_bytep rp
, end
, table
;
320 end
= row
+ row_info
->rowbytes
;
322 if (row_info
->bit_depth
== 1)
323 table
= onebppswaptable
;
324 else if (row_info
->bit_depth
== 2)
325 table
= twobppswaptable
;
326 else if (row_info
->bit_depth
== 4)
327 table
= fourbppswaptable
;
331 for (rp
= row
; rp
< end
; rp
++)
335 #endif /* PNG_READ_PACKSWAP_SUPPORTED or PNG_WRITE_PACKSWAP_SUPPORTED */
337 #if defined(PNG_WRITE_FILLER_SUPPORTED) || \
338 defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
339 /* remove filler or alpha byte(s) */
341 png_do_strip_filler(png_row_infop row_info
, png_bytep row
, png_uint_32 flags
)
343 png_debug(1, "in png_do_strip_filler\n");
344 #if defined(PNG_USELESS_TESTS_SUPPORTED)
345 if (row
!= NULL
&& row_info
!= NULL
)
349 if (row_info->color_type == PNG_COLOR_TYPE_RGB ||
350 row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
354 png_uint_32 row_width
=row_info
->width
;
357 if (row_info
->channels
== 4)
359 if (row_info
->bit_depth
== 8)
361 /* This converts from RGBX or RGBA to RGB */
362 if (flags
& PNG_FLAG_FILLER_AFTER
)
365 for (i
= 1; i
< row_width
; i
++)
373 /* This converts from XRGB or ARGB to RGB */
376 for (i
= 0; i
< row_width
; i
++)
384 row_info
->pixel_depth
= 24;
385 row_info
->rowbytes
= row_width
* 3;
387 else /* if (row_info->bit_depth == 16) */
389 if (flags
& PNG_FLAG_FILLER_AFTER
)
391 /* This converts from RRGGBBXX or RRGGBBAA to RRGGBB */
393 for (i
= 1; i
< row_width
; i
++)
395 /* This could be (although png_memcpy is probably slower):
396 png_memcpy(dp, sp, 6);
412 /* This converts from XXRRGGBB or AARRGGBB to RRGGBB */
413 for (i
= 0; i
< row_width
; i
++)
415 /* This could be (although png_memcpy is probably slower):
416 png_memcpy(dp, sp, 6);
430 row_info
->pixel_depth
= 48;
431 row_info
->rowbytes
= row_width
* 6;
433 row_info
->channels
= 3;
434 row_info
->color_type
&= ~PNG_COLOR_MASK_ALPHA
;
437 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY ||
438 row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
440 else if (row_info
->channels
== 2)
442 if (row_info
->bit_depth
== 8)
444 /* This converts from GX or GA to G */
445 if (flags
& PNG_FLAG_FILLER_AFTER
)
447 for (i
= 0; i
< row_width
; i
++)
453 /* This converts from XG or AG to G */
456 for (i
= 0; i
< row_width
; i
++)
462 row_info
->pixel_depth
= 8;
463 row_info
->rowbytes
= row_width
;
465 else /* if (row_info->bit_depth == 16) */
467 if (flags
& PNG_FLAG_FILLER_AFTER
)
469 /* This converts from GGXX or GGAA to GG */
471 for (i
= 1; i
< row_width
; i
++)
480 /* This converts from XXGG or AAGG to GG */
481 for (i
= 0; i
< row_width
; i
++)
488 row_info
->pixel_depth
= 16;
489 row_info
->rowbytes
= row_width
* 2;
491 row_info
->channels
= 1;
492 row_info
->color_type
&= ~PNG_COLOR_MASK_ALPHA
;
498 #if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
499 /* swaps red and blue bytes within a pixel */
501 png_do_bgr(png_row_infop row_info
, png_bytep row
)
503 png_debug(1, "in png_do_bgr\n");
505 #if defined(PNG_USELESS_TESTS_SUPPORTED)
506 row
!= NULL
&& row_info
!= NULL
&&
508 (row_info
->color_type
& PNG_COLOR_MASK_COLOR
))
510 png_uint_32 row_width
= row_info
->width
;
511 if (row_info
->bit_depth
== 8)
513 if (row_info
->color_type
== PNG_COLOR_TYPE_RGB
)
518 for (i
= 0, rp
= row
; i
< row_width
; i
++, rp
+= 3)
525 else if (row_info
->color_type
== PNG_COLOR_TYPE_RGB_ALPHA
)
530 for (i
= 0, rp
= row
; i
< row_width
; i
++, rp
+= 4)
538 else if (row_info
->bit_depth
== 16)
540 if (row_info
->color_type
== PNG_COLOR_TYPE_RGB
)
545 for (i
= 0, rp
= row
; i
< row_width
; i
++, rp
+= 6)
551 *(rp
+ 1) = *(rp
+ 5);
555 else if (row_info
->color_type
== PNG_COLOR_TYPE_RGB_ALPHA
)
560 for (i
= 0, rp
= row
; i
< row_width
; i
++, rp
+= 8)
566 *(rp
+ 1) = *(rp
+ 5);
573 #endif /* PNG_READ_BGR_SUPPORTED or PNG_WRITE_BGR_SUPPORTED */
575 #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
576 defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \
577 defined(PNG_LEGACY_SUPPORTED)
579 png_set_user_transform_info(png_structp png_ptr
, png_voidp
580 user_transform_ptr
, int user_transform_depth
, int user_transform_channels
)
582 png_debug(1, "in png_set_user_transform_info\n");
583 #if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
584 png_ptr
->user_transform_ptr
= user_transform_ptr
;
585 png_ptr
->user_transform_depth
= (png_byte
)user_transform_depth
;
586 png_ptr
->user_transform_channels
= (png_byte
)user_transform_channels
;
588 if(user_transform_ptr
|| user_transform_depth
|| user_transform_channels
)
590 "This version of libpng does not support user transform info");
595 /* This function returns a pointer to the user_transform_ptr associated with
596 * the user transform functions. The application should free any memory
597 * associated with this pointer before png_write_destroy and png_read_destroy
601 png_get_user_transform_ptr(png_structp png_ptr
)
603 #if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
604 return ((png_voidp
)png_ptr
->user_transform_ptr
);