Images of smaller page size PDF are not autoresized to full screen in iOS6 - ios6

I am trying to capture images from PDF and display them in my iPad application in a UIScrollView. App render the images to fullscreen (full size) when pdf page size is 1024 x 768 (standard 4:3 aspect ratio). But when the pdf page is of size 720 x 540 (same 4:3 aspect ratio but with less dimensions) I am seeing white border around the image. Below is the code snippet that i tried to capture the images.
CGPDFPageRef thePDFPageRef = CGPDFDocumentGetPage(pdfDocRef, pdfIterator);
CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB(); // RGB color space
CGBitmapInfo bmi = (kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedLast);
thumbnailWidth = 1024;
thumbnailHeight = 768;
CGContextRef context = CGBitmapContextCreate(NULL, thumbnailWidth, thumbnailHeight, 8, 0, rgb, bmi);
if (context != NULL) // Must have a valid custom CGBitmap context to draw into
{
CGRect thumbRect = CGRectMake(0.0f, 0.0f, thumbnailWidth, thumbnailHeight); // Target thumb rect
CGContextSetRGBFillColor(context, 1.0f, 1.0f, 1.0f, 1.0f);
CGContextFillRect(context, thumbRect); // White fill
CGContextConcatCTM(context, CGPDFPageGetDrawingTransform(thePDFPageRef, kCGPDFCropBox, thumbRect, 0, true)); // Fit rect
CGContextSetRenderingIntent(context, kCGRenderingIntentDefault);
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
CGContextDrawPDFPage(context, thePDFPageRef); // Render the PDF page into the custom CGBitmap context
imageRef = CGBitmapContextCreateImage(context); // Create CGImage from custom CGBitmap context
CGContextRelease(context); // Release custom CGBitmap context reference
}
CGColorSpaceRelease(rgb); // Release device RGB color space reference
CGPDFPageRelease(thePDFPageRef);
}
UIImage *image = [UIImage imageWithCGImage:imageRef scale:scale orientation:0];
How can I auto scale to full screen even when pdf page size is smaller?

I found the solution as below with scaling to rectangle.
(1) Get PDF page rectangle using
CGRect pageRect = CGPDFPageGetBoxRect(page, kCGPDFMediaBox);
(2) Do scale the rectangle and apply transform to Identity Matrix
CGAffineTransform trans = CGAffineTransformIdentity;
trans = CGAffineTransformTranslate(trans, 0, pageRect.size.height);
trans = CGAffineTransformScale(trans, 1.0, -1.0);
rect = CGRectApplyAffineTransform(rect, trans);
(3) Use kCGPDFMediaBox instead of kCGPDFCropBox to avoid cropping of pdfs when size is different than standard.

Related

Rotating sprite with a center of rotation in SDL2

I want to rotate a sprite in C and SDL2, with a set center of rotation, and without scaling or anti-aliasing.
My game resolution is 320x240, and the display is scaled up when I set the game to full screen, because I'm using SDL_RenderSetLogicalSize(renderer, 320, 240).
Using SDL2's SDL_RenderCopyEx() (or SDL_RenderCopyExF()) to rotate a SDL_Texture.
As shown in this example ( https://imgur.com/UGNDfEY ) when the window is set to full screen, the texture is scaled up and at much higher resolution. Is would like the final 320x240 rendering to be scaled up, not the individual textures.
Using SDL_gfx's rotozoomSurface() was a possible alternative.
However, as shown in this example ( https://imgur.com/czPEUhv ), while this method give the intended low-resolution and aliased look, it has no center of rotation, and renders the transparency color as half-transparent black.
Is there a function that does what I'm looking for? Are there some tricks to get around that?
What I would do is to render what you want to in a SDL_Texture, and then print this texture into the renderer, using something like :
// Set 'your_texture' as target
SDL_SetRenderTarget(your_renderer, your_texture);
// We are now printing the rotated image on the texture
SDL_RenderCopyEx(your_renderer, // we still use the renderer; it will be automatically printed into the texture 'your_texture'
your_image,
&srcrect,
&dstrect,
angle,
&center,
SDL_FLIP_NONE); // unless you want to flip vertically / horizontally
// Set the renderer as target and print the previous texture
SDL_SetRenderTarget(your_renderer, NULL);
SDL_RenderClear(your_renderer);
SDL_RenderCopy (your_renderer, your_texture, NULL, NULL); // here the scale is automatically done
SDL_RenderPresent(your_renderer);
It works, but I don't know if it is very efficient.
Don't forget to define your_texture with a SDL_TEXTUREACCESS_TARGET access.
Hope this helps,
Durza42
Thanks to #Durza42, here's the solution to my problem:
#define kScreenWidth 320
#define kScreenHeight 240
SDL_Window* g_window = NULL;
SDL_Texture* g_texture = NULL;
SDL_Renderer* g_renderer = NULL;
SDL_Texture* g_sprite = NULL;
double g_sprite_angle = 0.0;
SDL_FRect g_sprite_frect = {
.x = 50.0f,
.y = 50.0f,
.w = 32.0f,
.h = 32.0f,
};
void
sdl_load(void)
{
SDL_Init(SDL_INIT_VIDEO);
g_window = SDL_CreateWindow(NULL, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, kScreenWidth, kScreenHeight, 0);
g_renderer = SDL_CreateRenderer(g_window, -1, SDL_RENDERER_PRESENTVSYNC);
g_texture = SDL_CreateTexture(g_renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, kScreenWidth, kScreenHeight);
SDL_RenderSetLogicalSize(g_renderer, kScreenWidth, kScreenHeight);
}
void
sprite_load(void)
{
g_sprite = IMG_LoadTexture(g_renderer, "./sprite.png");
}
void
draw(void)
{
SDL_SetRenderTarget(g_renderer, g_texture);
SDL_RenderClear(g_renderer);
SDL_RenderCopyExF(g_renderer, g_sprite, NULL, &g_sprite_frect, g_sprite_angle, NULL, SDL_FLIP_NONE);
SDL_SetRenderTarget(g_renderer, NULL);
SDL_RenderClear(g_renderer);
SDL_RenderCopy(g_renderer, g_texture, NULL, NULL);
SDL_RenderPresent(g_renderer);
}

Cairo Library: produce a png file with white background

I searched in INTERNET related to the subject but I found only people that want to save png file with the background transparent.
I report belove the source code that at the moment I use and produces png with background transparent:
cairo_surface_t *surface; // Declarations
cairo_t *cr;
// Creations of the surface
surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,3508,2480);
// Contest
cr = cairo_create(surface);
// Moving the plot to center in the page
cairo_translate(cr, 200,200);
// Scaling the plot
cairo_scale(cr,1.8,1.8);
// Make all the necessary actions to produce the plot
do_drawing(cr);
// write the plot on the file png
cairo_surface_write_to_png(surface, "image.png");
// End
cairo_surface_destroy(surface);
cairo_destroy(cr);
I used also the surface CAIRO_FORMAT_RGB24 but I obtain a black rectangle like plot.
Please could you help me?
Thank You
cairo_surface_t *surface; // Declarations
cairo_t *cr;
// Creations of the surface
// XXX: Changed to format RGB24; if you don't need transparency, well.
surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24,3508,2480);
// Contest
cr = cairo_create(surface);
// Draw background XXXXXXXXXXXXXXXXXX
cairo_save(cr);
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_paint(cr);
cairo_restore(cr);
// Moving the plot to center in the page
cairo_translate(cr, 200,200);
// Scaling the plot
cairo_scale(cr,1.8,1.8);
// Make all the necessary actions to produce the plot
do_drawing(cr);
// write the plot on the file png
cairo_surface_write_to_png(surface, "image.png");
// End
cairo_surface_destroy(surface);
cairo_destroy(cr);
You need to draw with an opaque background, take a look at the cairo_set_source_rgb function.

WPF - Black Background surrounding saved canvas as jpeg

I'm having difficulty with JpegBitmapEncoder since it is creating an image that is placed in black rectangle. and I don't have the solution for fix.
private void SaveImage(Canvas canvas, string fileName)
{
SaveFileDialog s = new SaveFileDialog();
s.FileName = "Pic";
s.DefaultExt = ".jpg";
s.Filter = "JPG files (.jpg)|*.jpg";
Nullable<bool> result = s.ShowDialog();
if (result == true)
{
RenderTargetBitmap renderBitmap = new RenderTargetBitmap(6646, 3940, 2000d, 2000d, PixelFormats.Pbgra32);
canvas.Measure(new Size((int)canvas.Width, (int)canvas.Height));
canvas.Arrange(new Rect(new Size((int)canvas.Width, (int)canvas.Height)));
renderBitmap.Render(canvas);
string filename = s.FileName;
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
using (FileStream file = File.Create(filename))
{
encoder.Save(file);
}
}
}
with this code i get:
but when i use PngBitmap Encoder this doesn't happen. Can anyone shine a light?
How do I remove the black rectangle or perhaps fill it by increasing the dimensions of the picture?
.png supports transparency, whereas .jpg doesn't. I suspect that the background of your canvas is transparent, and as it doesn't know what to do with it it just leaves the pixels default (0,0,0) i.e. black. Png defaults to (0,0,0,0), which is transparent black.
Or, your canvas isn't the same dimensions as the image (your create your image with hardcoded width & height, rather than use the Width and Height of your canvas). As it's larger, it only renders the parts where the canvas actually covers.
If it's the first case, try setting your canvas Background="White" to your canvas so it renders all of it with no transparency. If it's the second, try creating a Rectangle the dimensions of your image with the appropriate Fill="White" and rendering that first before your canvas. Something like this:
Rectangle fillBackground = new Rectangle {
Width = 6646,
Height = 3940,
Fill=Brushes.White
}
renderBitmap.Render(fillBackground);
renderBitmap.Render(canvas);
Some advice, you shouldn't really use Width and Height, these can be NAN for a control that's layout is determined by it's parent. You should actually use Canvas.ActualWidth and Canvas.ActualHeight or Canvas.RenderSize.Width/Height. This will actually reflect the on-screen size all the time.
Also, to calculate the size of your output image adjusting for your DPI choice you can use the following:
RenderTargetBitmap renderBitmap = new RenderTargetBitmap(Width * DPI/96,
Height * DPI/96,
DPI, DPI, PixelFormats.Pbgra32);

Why is pango_cairo_show_layout drawing text at a slightly wrong location?

I have a Gtk app written in C running on Ubuntu Linux.
I'm confused about some behavior I'm seeing with the pango_cairo_show_layout function: I get the exact "ink" (not "logical") pixel size of a pango layout and draw the layout using pango_cairo_show_layout on a GtkDrawingArea widget. Right before drawing the layout, I draw a rectangle that should perfectly encompass the text that I'm about to draw, but the text always shows up a little below the bottom edge of the rectangle.
Here is my full code:
// The drawing area widget's "expose-event" callback handler
gboolean OnTestWindowExposeEvent(GtkWidget *pWidget, GdkEventExpose *pEvent, gpointer data)
{
// Note that this window is 365 x 449 pixels
double dEntireWindowWidth = pEvent->area.width; // This is 365.0
double dEntireWindowHeight = pEvent->area.height; // This is 449.0
// Create a cairo context with which to draw
cairo_t *cr = gdk_cairo_create(pWidget->window);
// Draw a red background
cairo_set_source_rgb(cr, 1.0, 0.0, 0.0);
cairo_rectangle(cr, 0.0, 0.0, dEntireWindowWidth, dEntireWindowHeight);
cairo_fill(cr);
// Calculate the padding inside the window which defines the text rectangle
double dPadding = 0.05 * ((dEntireWindowWidth < dEntireWindowHeight) ? dEntireWindowWidth : dEntireWindowHeight);
dPadding = round(dPadding); // This is 18.0
// The size of the text box in which to draw text
double dTextBoxSizeW = dEntireWindowWidth - (2.0 * dPadding);
double dTextBoxSizeH = dEntireWindowHeight - (2.0 * dPadding);
dTextBoxSizeW = round(dTextBoxSizeW); // This is 329.0
dTextBoxSizeH = round(dTextBoxSizeH); // This is 413.0
// Draw a black rectangle that defines the area in which text may be drawn
cairo_set_line_width(cr, 1.0);
cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
cairo_rectangle(cr, dPadding, dPadding, dTextBoxSizeW, dTextBoxSizeH);
cairo_stroke(cr);
// The text to draw
std::string szText("Erik");
// The font name to use
std::string szFontName("FreeSans");
// The font size to use
double dFontSize = 153.0;
// The font description string
char szFontDescription[64];
memset(&(szFontDescription[0]), 0, sizeof(szFontDescription));
snprintf(szFontDescription, sizeof(szFontDescription) - 1, "%s %.02f", szFontName.c_str(), dFontSize);
// Create a font description
PangoFontDescription *pFontDescription = pango_font_description_from_string(szFontDescription);
// Set up the font description
pango_font_description_set_weight(pFontDescription, PANGO_WEIGHT_NORMAL);
pango_font_description_set_style(pFontDescription, PANGO_STYLE_NORMAL);
pango_font_description_set_variant(pFontDescription, PANGO_VARIANT_NORMAL);
pango_font_description_set_stretch(pFontDescription, PANGO_STRETCH_NORMAL);
// Create a pango layout
PangoLayout *pLayout = gtk_widget_create_pango_layout(pWidget, szText.c_str());
// Set up the pango layout
pango_layout_set_alignment(pLayout, PANGO_ALIGN_LEFT);
pango_layout_set_width(pLayout, -1);
pango_layout_set_font_description(pLayout, pFontDescription);
pango_layout_set_auto_dir(pLayout, TRUE);
// Get the "ink" pixel size of the layout
PangoRectangle tRectangle;
pango_layout_get_pixel_extents(pLayout, &tRectangle, NULL);
double dRealTextSizeW = static_cast<double>(tRectangle.width);
double dRealTextSizeH = static_cast<double>(tRectangle.height);
// Calculate the top left corner coordinate at which to draw the text
double dTextLocX = dPadding + ((dTextBoxSizeW - dRealTextSizeW) / 2.0);
double dTextLocY = dPadding + ((dTextBoxSizeH - dRealTextSizeH) / 2.0);
// Draw a blue rectangle which should perfectly encompass the text we're about to draw
cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
cairo_set_source_rgb(cr, 0.0, 0.0, 1.0);
cairo_rectangle(cr, dTextLocX, dTextLocY, dRealTextSizeW, dRealTextSizeH);
cairo_stroke(cr);
// Set up the cairo context for drawing the text
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
cairo_set_antialias(cr, CAIRO_ANTIALIAS_BEST);
// Move to the top left coordinate before drawing the text
cairo_move_to(cr, dTextLocX, dTextLocY);
// Draw the layout text
pango_cairo_show_layout(cr, pLayout);
// Clean up
cairo_destroy(cr);
g_object_unref(pLayout);
pango_font_description_free(pFontDescription);
return TRUE;
}
So, why is the text not being drawn exactly where I tell it to be drawn?
Thanks in advance for any help!
Look at the documentation for pango_layout_get_extents() (this is not mentioned in the docs for pango_layout_get_pixel_extents():
Note that both extents may have non-zero x and y. You may want to use
those to offset where you render the layout.
https://developer.gnome.org/pango/stable/pango-Layout-Objects.html#pango-layout-get-extents
This is because the position that you render the layout at is (as far as I remember) the position of the base line (so something logically related to the text) instead of the top-left corner of the layout (which would be some "arbitrary thing" not related to the actual text).
In the case of your code, I would suggest to add tRectangle.x to dTextLocX (or subtract? I'm not completely sure about the sign). The same should be done with the y coordinate.
TL;DR: Your PangoRectangle has a non-zero x/y position that you need to handle.
Edit: I am not completely sure, but I think Pango handles this just like cairo. For cairo, there is a nice description at http://cairographics.org/tutorial/#L1understandingtext. The reference point is the point you give to cairo. You want to look at the description of bearing.

Displaying RGBA images using Image class w/o pre-multiplied alpha

I'm trying to display the separate R, G, B and A channels of a texture based on user input. I'm using an Image class to display textures that have alpha channels. These textures are loaded in to BitmapSource objects and have a Format of Bgra32. The problem is that when I set the Image's Source to the BitmapSource, if I display any combination of the R, G or B channels, I always get pixels that are pre-multiplied by the alpha value. I wrote a really simple shader, pre-compiled it, and used a ShaderEffect class to assign to the Image's Effect property in order to separate and display the separate channels, but apparently, the shader is given the texture after WPF has pre-multiplied the alpha value onto the texture.
Here's the code snippet for setting the Image's Source:
BitmapSource b = MyClass.GetBitmapSource(filepath);
// just as a test, write out the bitmap to file to see if there's an alpha.
// see attached image1
BmpBitmapEncoder test = new BmpBitmapEncoder();
//test.Compression = TiffCompressOption.None;
FileStream stest = new FileStream(#"c:\temp\testbmp2.bmp", FileMode.Create);
test.Frames.Add(BitmapFrame.Create(b));
test.Save(stest);
stest.Close();
// effect is a class derived from ShaderEffect. The pixel shader associated with the
// effect displays the color channel of the texture loaded in the Image object
// depending on which member of the Point4D is set. In this case, we are showing
// the RGB channels but no alpha
effect.PixelMask = new System.Windows.Media.Media3D.Point4D(1.0f, 1.0f, 1.0f, 0.0f);
this.image1.Effect = effect;
this.image1.Source = b;
this.image1.UpdateLayout();
Here's the shader code (its pretty simple, but I figured I'd include it just for completeness):
sampler2D inputImage : register(s0);
float4 channelMasks : register(c0);
float4 main (float2 uv : TEXCOORD) : COLOR0
{
float4 outCol = tex2D(inputImage, uv);
if (!any(channelMasks.rgb - float3(1, 0, 0)))
{
outCol.rgb = float3(outCol.r, outCol.r, outCol.r);
}
else if (!any(channelMasks.rgb - float3(0, 1, 0)))
{
outCol.rgb = float3(outCol.g, outCol.g, outCol.g);
}
else if (!any(channelMasks.rgb - float3(0, 0, 1)))
{
outCol.rgb = float3(outCol.b, outCol.b, outCol.b);
}
else
{
outCol *= channelMasks;
}
if (channelMasks.a == 1.0)
{
outCol.r = outCol.a;
outCol.g = outCol.a;
outCol.b = outCol.a;
}
outCol.a = 1;
return outCol;
}
Here's the output from the code above:
(sorry, i don't have enough reputation points to post images or apparently more than 2 links)
The file save to disk (C:\temp\testbmp2.bmp) in photoshop:
http://screencast.com/t/eeEr5kGgPukz
Image as displayed in my WPF application (using image mask in code snippet above):
http://screencast.com/t/zkK0U5I7P7

Resources