Preserve Aspect, but with crop center - image

I have a GameObject with RawImage component displaying an Image using Texture.
The image is squeezed to the size of the object and changing it's original ratio.
How can I tell the image in the texture to CropCenter? (like in Android for example)

Here is how I do with landscape images :
Create a parent RawImage element called "Mask" (works with UI > Image component too)
Add the UI > Mask component to it
Put your Smurf image (with the `RawImage component) as a child of the "Mask" object
Set the values of the child'RectTransform :
Anchors Min = (0.5, 0),
Anchors Max = (0.5, 1)
Top = 0
Bottom = 0
Add the Layout > Aspect Ratio Fitter to the Smurf image and set the Aspect Mode to "Height Controls Width" and the Aspect Ratio to the desired value (16/9 for example)
Check the image : Parent called "Mask" and your smurf image called "Image"
For portrait images, the RectTransform values :
Anchors Min = (0, 0.5),
Anchors Max = (1, 0.5)
Left = 0
Right = 0
The Aspect Mode of the child must be set to "Width Controls Heigh"

Related

Draw polygon extending beyond image-border

Note:
The question is specific to PHP GD library only
This question is NOT about how to crop image to a target aspect ratio, rather it is about how to draw overlay extending outside the image
I want to create custom graphic by putting together a background image with a polygon and some texts.
Input background images are of varied dimensions and aspect-ratios, but the final graphic has to be of a fixed (2:1) aspect ratio (it also has to be of pre-defined dimensions, but resizing of image is trivial, so correct aspect ratio is my only target).
Presently I'm cropping-to-fit my input image to target aspect ratio (2:1) by performing max-center area cropping using imagecrop function. Thereafter I draw red polygon on it as shown below (ignore the texts drawn on red band) using imagefilledpolygon method [cropping screenshot below is for demonstration purpose only, it is actually being done programmatically via imagecrop function]
Here's my function that draws the overlay (this function is called after cropping of image to 2:1 aspect ratio is done)
/**
* adds overlay (colored band) on the image
* for better output, overlay must be added before resizing
*/
public function withOverlay(): NotifAdsCreativeGenerator {
// Prepare custom red-color Hex to RGB https://stackoverflow.com/a/15202130/3679900
list($r, $g, $b) = sscanf(self::OVERLAY_COLOR, "#%02x%02x%02x");
$custom_red_color = imagecolorallocate($this->getCrrImage(), $r, $g, $b);
// prepare coordinates for polygon
$coords = [
[0, 0],
[(int) ($this->getCrrWidth() * self::OVERLAY_BEGIN_X_RATIO), 0],
[(int) ($this->getCrrWidth() * self::OVERLAY_END_X_RATIO), $this->getCrrHeight()],
[0, $this->getCrrHeight()]
];
$flattened_coords = array_merge(...$coords);
// draw polygon on image
imagefilledpolygon($this->getCrrImage(), $flattened_coords, count($flattened_coords) / 2, $custom_red_color);
return $this;
}
But what I want is to crop the image to ~ 1.28:1 aspect ratio (the approx ratio of right part of graphic without the red band) and then draw the polygon (extending) outside the image so as to obtain the final graphic in the same same 2:1 aspect ratio as shown below
I'm able to crop image to my desired aspect ratio (1.28:1) but I can't figure out a way to draw the polygon outside the image bounds (effectively expanding the image in the process). Is there a way to do this using PHP-GD library?
It was just a lack of understanding (about working of PHP-GD, available methods) on my part, but the solution is pretty simple
create an empty 'canvas' image of desired dimensions (and the 2:1 target aspect ratio) using imagecreatetruecolor function
(after cropping), copy the image on right side of canvas using imagecopy method (some basic maths has to be done to determine the offset where the image has to be placed on canvas)
now as before, the red polygon can be drawn on the left side on canvas to obtain the final graphic
/**
* adds overlay (colored band) on the image
* for better output, overlay must be added before resizing
*
* This method tries to preserve maximum center region of input image by performing minCenterCrop(.) on it
* before drawing an overlay that extends beyond left border of the cropped image
*
* (since this method incorporates call to 'withMinCenterCrop', calling that method before this is not required
* (and is redundant). For benefits of this method over 'withOverlay', read docstring comment of
* 'withMinCenterCrop' method
* #return NotifAdsCreativeGenerator
*/
public function withExtendedOverlay(): NotifAdsCreativeGenerator {
// perform min center crop to the 1.28:1 aspect ratio (preserve max central portion of image)
$this->withMinCenterCrop();
// this $required_canvas_aspect_ratio calculates to 2.0 (2:1 aspect ratio)
// calculate aspect ratio & dimensions of empty 'canvas' image
// since canvas is wider than min center-cropped image (as space on the left will be occupied by red overlay)
// therefore it's height is matched with cropped image and width is calculated
$required_canvas_aspect_ratio = self::IMAGE_WIDTH / self::IMAGE_HEIGHT;
// height of cropped image
$canvas_height = $this->getCrrHeight();
$canvas_width = $required_canvas_aspect_ratio * $canvas_height;
// create a new 'canvas' (empty image) on which we will
// 1. draw the existing input 'min-cropped' image on the right
// 2. draw the red overlay on the left
$canvas_image = imagecreatetruecolor($canvas_width, $canvas_height);
// copy contents of image on right side of canvas
imagecopy(
$canvas_image,
// cropped image
$this->getCrrImage(),
self::OVERLAY_BEGIN_X_RATIO * $canvas_width,
0,
0,
0,
// dimensions of cropped image
$this->getCrrWidth(),
$this->getCrrHeight()
);
// draw red band overlay on left side of canvas
$this->crr_image = $canvas_image;
return $this->withOverlay();
}

iTextSharp ultra wide image in multiple pages horizontally

I have a problem with iTextSharp. I have an image of 20000x1000 and I have to put it in a PDF with page size A1 horizontal. The tricky thing is that I need to adjust the height of the image to the PDF and print multiple pages wide in relation to the image.
I tried with this but it generates a PDF with a single page and the image adjusted both width and height.
Rectangle pageSize = PageSize.A1;
Document doc = new Document(pageSize.Rotate(), 10f, 10f, 10f, 10f);
PdfWriter writer = PdfWriter.GetInstance(doc, new FileStream(#"C:\TestFiles\Default.pdf", FileMode.Create));
doc.Open();
Image image = Image.GetInstance(#"C:\TestFiles\image.png");
PdfPTable table = new PdfPTable(1);
table.WidthPercentage = 100;
PdfPCell c = new PdfPCell(image, true);
c.Border = PdfPCell.NO_BORDER;
c.Padding = 5;
c.Image.ScaleAbsoluteHeight(pageSize.Height);
table.AddCell(c);
doc.Add(table);
doc.Close();
Thank you in advance for your help.
Using a table is not the way to go for your requirement.
First let's take a look at how you can scale the image so that the height is adapted to the height of a rotated A1 document:
Image image = Image.GetInstance(#"C:\TestFiles\image.png");
image.ScaleToFit(image.ScaledWidth, PageSize.A1.Width);
The ScaleToFit() method scales an image so that it fits into a rectangle. In this case, we don't want the width to be reduced, so we define the width of that rectangle as equal to the width of the original image. We do want to scale the height so that it fits the height of a rotated A1 page. As we rotate the A1 page, we have to use PageSize.A1.Width instead of PageSize.A1.Height.
Suppose that you have an image that measures 500 x 1500, then the scaled image will have size 500 by 2000 because that image fits a rectangle of 500 by 1684.
Suppose that you have an image that measures 500 x 2000, then the scaled image will be 421 x 1684. The height will be reduced to fit the rotated A1 page, and the width will be reduced accordingly.
Suppose that you have an image of 5000 by 2000, then the scaled image will be 4210 x 1684.
Now we have to add the same image as many times as needed until the complete image is rendered. Note that the image bytes will only be stored once in the PDF: those bytes are reused for every page.
Float offset = 0;
while (offset <= img.ScaledWidth) {
document.NewPage();
img.SetAbsolutePosition(-offset, 0);
document.Add(img);
offset += PageSize.A1.HEIGHT;
}
What happens in the above code snippet? On the first page, we add the image at position (0, 0) which is means that the lower-left corner of the image will coincide with the lower left corner of the page.
If the image fits the page, e.g. in case the width was scaled smaller than the new offset (2384), no new page will be triggered. If the image doesn't fit the page (e.g. because the scaled width is 4210 which is greater than 2384) a new page will be created, and the same image will be added with a new offset (e.g. (-2384, 0)).
Suppose that the width of the scaled image is indeed 4210 and the width of the page is 2384, then the offset after a second page is added will be 4768. That is greater than 4210, so there will be no third page.

Give 2d image customization to produce real view

Is it possible to add image/text on the 2d image so that it gives a real view.For example as present in : http://www.zazzle.com/make_your_own_iphone_5_case-179092402149274498.
These views are orthographic and isometric views and they can be reproduced using affine transformations in canvas, as they are also parallelograms.
First you will need to make masks for the different cases. These needs to be drawn in the same orientation as the case in the "photo". Use solid pixels (any color will do, it won't show in later step) where you want the custom graphics to show, transparent pixels anywhere else (anti-aliased pixels are fine).
Then draw in the mask in the canvas, select composite mode "source-in" to replace non-transparent pixels and finally, select blending mode "multiply" and draw the case "photo" on top to mix in shadows and highlights. The latter step is what will give the illusion of the image having depth.
For the isometric views, calculate the skew angle (or use trial and error if you're not sure if the image is accurate - this is as a rule-of-thumb usually tan(60°), ie. transform(1, 0, Math.tan(60/180*Math.PI), 1, 0, 0)), then do the same process as above. Just remember only apply transformation when drawing the custom image, mask and top layer must be drawn without transformations.
The orthographic side views can be generated using scaling for the x-axis. Depending on which angle, add a stripe for the side of the case.
Example of steps
var img = new Image(),
cust = new Image(),
count = 2,
ctx = document.querySelector("canvas").getContext("2d");
img.onload = cust.onload = comp;
img.src = "http://i.stack.imgur.com/je0Jh.png";
cust.src = "http://i.stack.imgur.com/uRPDt.png";
function comp() {
if (--count) return;
// draw in mask
ctx.drawImage(img, 0, 0);
// comp. mode source-in
ctx.globalCompositeOperation = "source-in";
// draw in custom graphics
ctx.drawImage(cust, 0, 0, ctx.canvas.width, ctx.canvas.height);
// blend mode multiply
ctx.globalCompositeOperation = "multiply";
// draw in original case multiplied (does not work in IE)
ctx.drawImage(img, 0, 0);
}
<canvas with=263 height=505></canvas>
The quality largely depends on the quality of the mask - I made a very quick-n-dirty version here as you can see (your case image can also act as the mask btw).
The steps are the same for the isometric view with the exception of the skew transform. Multiply does not work in IE, you can use alpha here instead or make a separate mask containing only shadows etc.
That being said: remember that this is not the image sent to production. This will just show a representation of the final result. What is used is the image, image position and size. These data is then used to build an unmasked flat print-template which is used to make the phone-case.

how to change the color of one portion of an image to another portion of the same image using MATLAB

I have a color image. The image consists of an object which has a shadow. I have removed the shadow but the shadow portion's color is not similar with the background color .Now how can I match the color using MATLAB coding?
You can change the matlab matrix (here called IMG) that corresponds to your image. For example, say that you changed the pixels of the shadows to -20.
Than you can get their indexes doing
indexes = (IMG == -20)
To change those values to the background color, assumed equals 100 for example, you set than doing
IMG(indexes) = 100
Since you're working with color images, you will need to do this for all the three color matrices that corresponds to your image. In this case you will have a background color for each layer, than you just repeat the process
indexes1 = (IMG(:, :, 1) == shadow_color_layer_1)
indexes2 = (IMG(:, :, 2) == shadow_color_layer_2)
indexes3 = (IMG(:, :, 3) == shadow_color_layer_3)
IMG(indexes,1) = background_color_layer_1
IMG(indexes,2) = background_color_layer_2
IMG(indexes,3) = background_color_layer_3

Color map and color bar of the overlaid index image on a gray scale background image?

I use following example codes to overlay an index image on a background image (in the example below it is RGB but for my problem the background is a gray sacle image). Then my questions are:
How to display the colorbar on the side of the overlaid image? The colorbar should be the colorbar of the overlaid index image NOT the colorbar of the background image.
How to fix the color map range of the overlaid index image? I have several pairs of gray scale background + overlaid index image (using 'jet' color map). I need them to be shown in the same scale. I try to use set(iim2,'caxis', [0 1]); but the 'image' in Matlab hasn't got the property of 'caxis'.
Please help and thanks very much!
% Create the background
% This example uses a blend of colors from left to right, converted to a TrueColor image
% Use repmat to replicate the pattern in the matrix
% Use the "jet" colormap to specify the color space
bg = ind2rgb(repmat(1:64,64,1),jet(64));
% Create an image and its corresponding transparency data
% This example uses a random set of pixels to create a TrueColor image
im = rand(100,100,3);
% Make the image fade in from left to right by designing its alphadata
% Use repmat to replicate the pattern in the transparency fading
imAlphaData = repmat(0:1/size(im,2):1-1/size(im,2),size(im,1),1);
% Display the images created in subplots
hf = figure('units','normalized','position',[.2 .2 .6 .6]);
ax1 = subplot(2,3,1);
ibg = image(bg);
axis off
title('Background')
ax2 = subplot(2,3,4);
iim = image(im);
axis off
title('Image without transparency yet')
% Now set up axes that overlay the background with the image
% Notice how the image is resized from specifying the spatial
% coordinates to locate it in the axes.
ax3 = subplot(2,3,[2:3, 5:6]);
ibg2 = image(bg);
axis off
hold on
% Overlay the image, and set the transparency previously calculated
iim2 = image(im,'XData',[30 50],'YData',[10 30]);
set(iim2,'AlphaData',imAlphaData);
title(sprintf('Using transparency while overlaying images:\nresult is multiple image objects.'))

Resources