Skip to content

Commit 03c64c2

Browse files
committed
[[ Bug 15324 ]] Convert image pixel format before sending to custom printer
1 parent d586466 commit 03c64c2

3 files changed

Lines changed: 110 additions & 46 deletions

File tree

docs/notes/bugfix-15324.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# in iOS, RGB values of exported images printed to PDF are reversed

engine/include/customprinter.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,12 @@ enum MCCustomPrinterImageType
112112
kMCCustomPrinterImagePNG
113113
};
114114

115+
#ifdef __LITTLE_ENDIAN__
116+
#define kMCCustomPrinterImagePixelFormat kMCGPixelFormatBGRA
117+
#else
118+
#define kMCCustomPrinterImagePixelFormat kMCGPixelFormatARGB
119+
#endif
120+
115121
struct MCCustomPrinterImage
116122
{
117123
MCCustomPrinterImageType type;

engine/src/customprinter.cpp

Lines changed: 103 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,67 @@ static MCCustomPrinterImageType MCCustomPrinterImageTypeFromMCGRasterFormat(MCGR
133133

134134
////////////////////////////////////////////////////////////////////////////////
135135

136+
bool MCCustomPrinterImageFromMCGImage(MCGImageRef p_image, MCCustomPrinterImage &r_image, void *&r_pixel_cache)
137+
{
138+
MCGRaster t_raster;
139+
if (!MCGImageGetRaster(p_image, t_raster))
140+
return false;
141+
142+
void *t_pixels;
143+
t_pixels = nil;
144+
145+
void *t_pixel_cache;
146+
t_pixel_cache = nil;
147+
148+
if (kMCCustomPrinterImagePixelFormat == kMCGPixelFormatNative)
149+
t_pixels = t_raster.pixels;
150+
else
151+
{
152+
if (!MCMemoryAllocate(t_raster.stride * t_raster.height, t_pixel_cache))
153+
return false;
154+
155+
uint8_t *t_src;
156+
t_src = (uint8_t*)t_raster.pixels;
157+
158+
uint8_t *t_dst;
159+
t_dst = (uint8_t*)t_pixel_cache;
160+
161+
for (uint32_t i = 0; i < t_raster.height; i++)
162+
{
163+
uint32_t *t_src_row;
164+
t_src_row = (uint32_t*)t_src;
165+
166+
uint32_t *t_dst_row;
167+
t_dst_row = (uint32_t*)t_dst;
168+
169+
for (uint32_t i = 0; i < t_raster.width; i++)
170+
*t_dst_row++ = MCGPixelFromNative(kMCCustomPrinterImagePixelFormat, *t_src_row++);
171+
172+
t_src += t_raster.stride;
173+
t_dst += t_raster.stride;
174+
}
175+
176+
t_pixels = t_pixel_cache;
177+
}
178+
179+
// Fill in the printer image info
180+
r_image.width = t_raster.width;
181+
r_image.height = t_raster.height;
182+
183+
bool t_mask, t_alpha;
184+
t_mask = !MCGImageIsOpaque(p_image);
185+
t_alpha = t_mask && MCGImageHasPartialTransparency(p_image);
186+
// IM-2014-06-26: [[ Bug 12699 ]] Set image type appropriately.
187+
r_image . type = t_alpha ? kMCCustomPrinterImageRawARGB : (t_mask ? kMCCustomPrinterImageRawMRGB : kMCCustomPrinterImageRawXRGB);
188+
r_image . id = (uint32_t)(intptr_t)p_image;
189+
r_image . data = t_pixels;
190+
r_image . data_size = t_raster.stride * t_raster.height;
191+
192+
r_pixel_cache = t_pixel_cache;
193+
194+
return true;
195+
}
196+
136197
class MCCustomMetaContext: public MCMetaContext
137198
{
138199
public:
@@ -500,43 +561,31 @@ void MCCustomMetaContext::doimagemark(MCMark *p_mark)
500561
t_image_type = kMCCustomPrinterImageNone;
501562
}
502563

503-
uint2 t_img_width, t_img_height;
504-
MCGRaster t_raster;
505-
506-
if (!m_execute_error)
507-
{
508-
if (!MCGImageGetRaster(p_mark->image.descriptor.image, t_raster))
509-
m_execute_error = true;
510-
}
511-
564+
void *t_pixel_cache;
565+
t_pixel_cache = nil;
566+
567+
// Fill in the printer image info
568+
MCCustomPrinterImage t_image;
512569
if (!m_execute_error)
513570
{
514-
t_img_width = t_raster.width;
515-
t_img_height = t_raster.height;
516-
517-
// Fill in the printer image info
518-
MCCustomPrinterImage t_image;
519571
if (t_image_type == kMCCustomPrinterImageNone)
520572
{
521-
bool t_mask, t_alpha;
522-
t_mask = !MCGImageIsOpaque(p_mark->image.descriptor.image);
523-
t_alpha = t_mask && MCGImageHasPartialTransparency(p_mark->image.descriptor.image);
524-
// IM-2014-06-26: [[ Bug 12699 ]] Set image type appropriately.
525-
t_image . type = t_alpha ? kMCCustomPrinterImageRawARGB : (t_mask ? kMCCustomPrinterImageRawMRGB : kMCCustomPrinterImageRawXRGB);
526-
t_image . id = (uint32_t)(intptr_t)p_mark->image.descriptor.image;
527-
t_image . data = t_raster.pixels;
528-
t_image . data_size = t_raster.stride * t_img_height;
573+
if (!MCCustomPrinterImageFromMCGImage(p_mark -> image . descriptor . image, t_image, t_pixel_cache))
574+
m_execute_error = true;
529575
}
530576
else
531577
{
532578
t_image . type = t_image_type;
533579
t_image . id = (uint32_t)(intptr_t)p_mark -> image . descriptor . data_bits;
534580
t_image . data = p_mark -> image . descriptor . data_bits;
535581
t_image . data_size = p_mark -> image . descriptor . data_size;
582+
t_image . width = MCGImageGetWidth(p_mark -> image . descriptor . image);
583+
t_image . height = MCGImageGetHeight(p_mark -> image . descriptor . image);
536584
}
537-
t_image . width = t_img_width;
538-
t_image . height = t_img_height;
539-
585+
}
586+
587+
if (!m_execute_error)
588+
{
540589
// Compute the transform that is needed - this transform goes from image
541590
// space to page space.
542591
// IM-2014-06-26: [[ Bug 12699 ]] Rework to ensure transforms are applied in the correct order - page transform -> image offset -> image transform
@@ -554,6 +603,9 @@ void MCCustomMetaContext::doimagemark(MCMark *p_mark)
554603
if (!m_device -> DrawImage(t_image, MCCustomPrinterTransformFromMCGAffineTransform(t_transform), t_clip))
555604
m_execute_error = true;
556605
}
606+
607+
if (t_pixel_cache != nil)
608+
MCMemoryDeallocate(t_pixel_cache);
557609
}
558610

559611
void MCCustomMetaContext::dolinkmark(MCMark *p_mark)
@@ -653,12 +705,11 @@ void MCCustomMetaContext::endcomposite(MCRegionRef p_clip_region)
653705
MCGContextRelease(m_composite_context);
654706
m_composite_context = nil;
655707

708+
void *t_pixel_cache;
709+
t_pixel_cache = nil;
710+
656711
if (t_success)
657712
{
658-
MCGRaster t_raster;
659-
660-
MCGImageGetRaster(t_image, t_raster);
661-
662713
/* OVERHAUL - REVISIT: Disabling the mask stuff for now, just treat the composite image as ARGB */
663714

664715
// Make sure the region is in logical coords.
@@ -678,12 +729,8 @@ void MCCustomMetaContext::endcomposite(MCRegionRef p_clip_region)
678729
// Now we have a masked image, issue an appropriate image rendering call to the
679730
// device
680731
MCCustomPrinterImage t_img_data;
681-
t_img_data . type = kMCCustomPrinterImageRawARGB;
682-
t_img_data . id = 0;
683-
t_img_data . width = t_raster . width;
684-
t_img_data . height = t_raster . height;
685-
t_img_data . data = t_raster . pixels;
686-
t_img_data . data_size = t_raster . stride * t_raster . height;
732+
733+
t_success = MCCustomPrinterImageFromMCGImage(t_image, t_img_data, t_pixel_cache);
687734

688735
MCCustomPrinterTransform t_img_transform;
689736
t_img_transform . scale_x = m_scale_x / m_composite_scale;
@@ -705,6 +752,12 @@ void MCCustomMetaContext::endcomposite(MCRegionRef p_clip_region)
705752
// m_execute_error = true;
706753
}
707754

755+
if (t_image != nil)
756+
MCGImageRelease(t_image);
757+
758+
if (t_pixel_cache != nil)
759+
MCMemoryDeallocate(t_pixel_cache);
760+
708761
m_execute_error = !t_success;
709762

710763
// Delete the region
@@ -787,6 +840,12 @@ void MCCustomMetaContext::dorawpathmark(MCMark *p_mark, uint1 *p_commands, uint3
787840
MCCustomPrinterGradientStop *t_paint_stops;
788841
t_paint_stops = nil;
789842

843+
MCGImageRef t_image;
844+
t_image = nil;
845+
846+
void *t_pixel_cache;
847+
t_pixel_cache = nil;
848+
790849
// Note we have to check the fill in this order since 'gradient' is not
791850
// a fill style and is indicated by the gradient field not being nil.
792851
if (p_mark -> fill -> gradient != nil)
@@ -835,29 +894,21 @@ void MCCustomMetaContext::dorawpathmark(MCMark *p_mark, uint1 *p_commands, uint3
835894
else if (p_mark -> fill -> style == FillTiled)
836895
{
837896
// Fetch the size of the tile, and its data.
838-
MCGImageRef t_image;
839-
t_image = nil;
840897

841898
MCGAffineTransform t_transform;
842899

843900
// IM-2014-05-13: [[ HiResPatterns ]] Update pattern access to use lock function
844901
if (MCPatternLockForContextTransform(p_mark->fill->pattern, MCGAffineTransformMakeIdentity(), t_image, t_transform))
845902
{
846-
MCGRaster t_tile_raster;
847-
/* UNCHECKED */ MCGImageGetRaster(t_image, t_tile_raster);
848-
849903
t_transform = MCGAffineTransformTranslate(t_transform, p_mark->fill->origin.x, p_mark->fill->origin.y);
850904

851905
// Construct the paint pattern.
852906
t_paint . type = kMCCustomPrinterPaintPattern;
853-
t_paint . pattern . image . type = MCCustomPrinterImageTypeFromMCGRasterFormat(t_tile_raster . format);
854-
t_paint . pattern . image . id = (uint32_t)(intptr_t)p_mark -> fill -> pattern;
855-
t_paint . pattern . image . width = t_tile_raster . width;
856-
t_paint . pattern . image . height = t_tile_raster . height;
857-
t_paint . pattern . image . data = t_tile_raster . pixels;
858-
t_paint . pattern . image . data_size = t_tile_raster . stride * t_tile_raster . height;
859907
t_paint . pattern . transform = MCCustomPrinterTransformFromMCGAffineTransform(t_transform);
908+
if (!MCCustomPrinterImageFromMCGImage(t_image, t_paint . pattern . image, t_pixel_cache))
909+
m_execute_error = true;
860910

911+
MCGImageRetain(t_image);
861912
MCPatternUnlock(p_mark->fill->pattern, t_image);
862913
}
863914
else
@@ -942,6 +993,12 @@ void MCCustomMetaContext::dorawpathmark(MCMark *p_mark, uint1 *p_commands, uint3
942993

943994
if (t_paint_stops != nil)
944995
delete[] t_paint_stops;
996+
997+
if (t_image != nil)
998+
MCGImageRelease(t_image);
999+
1000+
if (t_pixel_cache != nil)
1001+
MCMemoryDeallocate(t_pixel_cache);
9451002
}
9461003
else
9471004
m_execute_error = true;

0 commit comments

Comments
 (0)