How can an image be cropped based on a set scale of random image? - asp.net

Working on allowing the upload of images which can range in a variety of size, then allowing to crop a predefined area of the image for a thumbnail.
The thumbnail size is predefined to 150x150. Using the Jcrop.js tool to select a section of the image.
Problem:
When displaying the uploaded image in a smaller size than the original image by implementing set height/width on the image rendered, then there is a scale factor that comes into play when selecting an area to crop.
You either have to scale down the cropping area proportionately or you have to scale the image in relation to the actual image's size in comparison to its displayed size.
Question:
How do I figure out the scale of the browser displayed image vs. original image? I am currently using the following code to save the image, but how would I take into consideration the scaling?
public static Image CropImage(Image originalImage, int x, int y, int width, int height)
{
var bmp = new Bitmap(width, height);
bmp.SetResolution(originalImage.HorizontalResolution, originalImage.VerticalResolution);
using (var graphic = Graphics.FromImage(bmp))
{
graphic.SmoothingMode = SmoothingMode.AntiAlias;
graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphic.PixelOffsetMode = PixelOffsetMode.HighSpeed;
graphic.DrawImage(originalImage, new Rectangle(0, 0, width, height), x, y, width, height, GraphicsUnit.Pixel);
return bmp;
}
}
Bonus Question:
Another problem I discovered, is that there seems to be no efficient way to transfer the original file's ImageFormat when creating a new Bitmap which creates a ImageFormatMemoryBMP and when you attempt to call Bitmap.Save(memorystream, original rawformat) it will blow up. And bitmap RawFormat has no setter.
So how can you set the format on a new bitmap?

I think perhaps that this problem is solved purely on the front end, no need to use any server side for this.
Jcrop has a built in scale factor handler.
http://deepliquid.com/content/Jcrop_Sizing_Issues.html
Now you can use this in two ways, as I understand it. Either to 'resize' the image for you on the front end using 'box sizing', or you can tell it the 'truesize' of the image and it will work out the scale factor and handle the coordinates for you on it's own.
Box sizing
$('#cropbox').Jcrop({ boxWidth: 450, boxHeight: 400 });
True Size
$.Jcrop('#cropbox',{ trueSize: [500,370] });
Using the true size method you will need to invoke jcrop using the api method:
http://deepliquid.com/content/Jcrop_API.html#API_Invocation_Method
var jcrop_api,
options = { trueSize: [500,370] };
$('#target').Jcrop(options,function(){
jcrop_api = this;
});
Good luck!

Related

How would I make a color relative to images in the background?

For example, if you go to Twitter and click on an image, you can see they have a nice color that is close to what you see on the image. I tried looking up ways to achieve this as well as trying to figure it out on my own but no luck. I'm not sure if there's a color: relative property or not.
if you want to use the a colour that exists in your image and set it as a background colour you need to use the canvas element in the following manner:
HTML (this is your image)
<img src="multicolour.jpg" id="mainImage">
JS
window.onload = function() {
// get the body element to set background (this can change dependending of your needs)
let body = document.getElementsByTagName("body")
// get references to the image element that contains the picture you want to match with background
let referenceImage = document.getElementById("mainImage");
// create a canvas element (but don't add it to the page)
let canvas = document.createElement("canvas");
// make the canvas size the same as your image
canvas.width = referenceImage.offsetWidth
canvas.height = referenceImage.offsetHeight
// create the canvas context
let context = canvas.getContext('2d')
// usage your image reference to draw the image in the canvas
context.drawImage(referenceImage,0,0);
// select a random X and Y coordinates inside the drawn image in the canvas
// (you don't have to do this one, but I did to demonstrate the code)
let randomX = Math.floor(Math.random() * (referenceImage.offsetWidth - 1) + 1)
let randomY = Math.floor(Math.random() * (referenceImage.offsetHeight - 1) + 1)
// THIS IS THE MOST IMPORTANT LINE
// getImageData takes 4 arguments: coord x, coord y, sample size w, and sample size h.
// in our case the sample size is going to be of 1 pixel so it retrieves only 1 color
// the method gives you the data object which constains and array with the r, b, g colour data from the selected pixel
let color = context.getImageData(randomX, randomY, 1, 1).data
// use the data to dynamically add a background color extracted from your image
body[0].style.backgroundColor = `rgb(${color[0]},${color[1]},${color[2]})`
}
here is a gif of the code working... hopefully this helps
UPDATE
Here is the code to select two random points and create a css3 background gradient
window.onload = function() {
// get the body element to set background (this can change dependending of your needs)
let body = document.getElementsByTagName("body")
// get references to the image element that contains the picture you want to match with background
let referenceImage = document.getElementById("mainImage");
// create a canvas element (but don't add it to the page)
let canvas = document.createElement("canvas");
// make the canvas size the same as your image
canvas.width = referenceImage.offsetWidth
canvas.height = referenceImage.offsetHeight
// create the canvas context
let context = canvas.getContext('2d')
// usage your image reference to draw the image in the canvas
context.drawImage(referenceImage,0,0);
// select a random X and Y coordinates inside the drawn image in the canvas
// (you don't have to do this one, but I did to demonstrate the code)
let randomX = Math.floor(Math.random() * (referenceImage.offsetWidth - 1) + 1)
let randomY = Math.floor(Math.random() * (referenceImage.offsetHeight - 1) + 1)
// THIS IS THE MOST IMPORTANT LINE
// getImageData takes 4 arguments: coord x, coord y, sample size w, and sample size h.
// in our case the sample size is going to be of 1 pixel so it retrieves only 1 color
// the method gives you the data object which constains and array with the r, b, g colour data from the selected pixel
let colorOne = context.getImageData(randomX, randomY, 1, 1).data
// THE SAME TO OBTAIN ANOTHER pixel data
let randomX2 = Math.floor(Math.random() * (referenceImage.offsetWidth - 1) + 1)
let randomY2 = Math.floor(Math.random() * (referenceImage.offsetHeight - 1) + 1)
let colorTwo = context.getImageData(randomX2, randomY2, 1, 1).data
// use the data to dynamically add a background color extracted from your image
//body[0].style.backgroundColor = `rgb(${allColors[0]},${allColors[1]},${allColors[2]})`
body[0].style.backgroundImage = `linear-gradient(to right, rgb(${colorOne[0]},${colorOne[1]},${colorOne[2]}),rgb(${colorTwo[0]},${colorTwo[1]},${colorTwo[2]}))`;
}
The following are your options.
1. Use an svg.
As far as I know there's no way to have javascript figure out what color is being used in a png and set it as a background color. But you can work the other way around. You can have javascript set the background color and an svg image to be the same color.
See this stackoverflow answer to learn more about modifying svgs with javascript.
2. Use a custom font.
There are fonts out there that provide a bunch of icons instead of letters, you can also create your own font if you feel so inclined to do so. With css you just have to set the font-color of that icon to be the same as the background-color of your other element.
Font Awesome provides a bunch of useful custom icons. If the image you need to use happens to be similar to one of theirs, you can just go with them.
3. Use canvas
If you really want to spend the time to code it up you can use a html <canvas/> element and put the image into it. From there you can inspect certain details about the image like its color, then apply that color to other elements. I won't go into too much detail about using this method as it seems like it's probably overkill for what you're trying to do, but you can read up more about from this stackoverflow answer.
4. Just live with it.
Not a fun solution, but this is usually the option I go with. You simply have to hard-code the color of the image into your css and live with it. If you ever need to modify the color of the image, you have to remember to update your css also.

How to save a high DPI snapshot of a JavaFX Canvas

I have created an image on a Canvas which is scaled down for display using a transformation. It is also in a ScrollPane which means only a part of the image is visible.
I need to take a snapshot of the entire canvas and save this as a high-resolution image. When I use Canvas.snapshot I get a Writable image of the visible part of the image after scaling down. This results in a low-res partial image being saved.
So how do I go about creating a snapshot which includes the entire canvas (not only the viewport of the scrollpane) and with the resolution before the transformation downwards?
I am not doing anything fancy currently, just this:
public WritableImage getPackageCanvasSnapshot()
{
SnapshotParameters param = new SnapshotParameters();
param.setDepthBuffer(true);
return packageCanvas.snapshot(param, null);
}
I did the following to get a canvas snapshot on a Retina display with a pixelScaleFactor of 2.0. It worked for me.
public static WritableImage pixelScaleAwareCanvasSnapshot(Canvas canvas, double pixelScale) {
WritableImage writableImage = new WritableImage((int)Math.rint(pixelScale*canvas.getWidth()), (int)Math.rint(pixelScale*canvas.getHeight()));
SnapshotParameters spa = new SnapshotParameters();
spa.setTransform(Transform.scale(pixelScale, pixelScale));
return canvas.snapshot(spa, writableImage);
}

JavaFX: maximum ImageView size

This may sound like a duplicate of Set maximum size for JavaFX ImageView but it's different.
I'd like to restrict the maximum size of an ImageView. Unfortunately, the only way to set the ImageView's size seems to be fitWidth and fitHeight which however enlarges the image if it's smaller than the fit values.
I tried setting fitWidth/fitHeight to 0/0 and wrap the ImageView into a pane with maxWidth set - no success (image is displayed in original size).
To me it seems as this is not achievable by JavaFX, however I can't believe it. But I couldn't find anything online. Are there any tricks/bugs/workarounds on this?
If you dont want the image to stretch, you can use:
setPreserveRatio(true);
Then you are able to fit width and height as you want
ImageView setPreserveRatio javadoc
In javadoc in this method there are the rules of scaling too
You just needed to add in if statement to set those larger than maxsize to a fixed size. The rest would remain their original size.
ImageView im = new ImageView();
im.setImage(image);
im.maxHeight(690 - 10);
int yoursize = 690;
if(im.maxHeight(690 - 10)> yoursize ){
im.setFitHeight(690- 10);
System.out.println("Fix Size : 690 ");
}
im.setPreserveRatio(true);
im.setSmooth(true);
im.setCache(true);
You can get the actual Image resource and query its width/height to use for the fit values:
Image image = imageView.getImage();
double nativeWidth = image.getWidth();
double nativeHeight = image.getHeight();

GtkToolButton with custom icon but of stock icon size

I've a GtkToolBar which has say 3 GtkToolButtons with each of these having a stock icon value, and hence they all appear in the same size; now I added a 4th GtkToolButton with a custom image (.png), which was of an arbitrary dimension and only this button ended up looking huge (since the image was of higher resolution). What do I do to scale this GtkToolButton to match the other 3 buttons?
Here's the code which does what I briefed about:
GtkWidget *custom_icon = gtk_image_new_from_file(path);
GtkToolItem *toolbar_item = gtk_toggle_tool_button_new();
gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(toolbar_item), custom_icon);
gtk_tool_button_set_label(GTK_TOOL_BUTTON(toolbar_item), "Custom Item");
gtk_toolbar_insert(toolbar, toolbar_item, -1);
Here is another solution.
GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(icon_file_path, NULL);
int width, height;
gdk_pixbuf_get_file_info (icon_file_path, &width, &height);
gtk_icon_theme_add_builtin_icon ("custom_icon", width, pixbuf);
g_object_unref (G_OBJECT (pixbuf));
GtkToolItem *toolbar_item = gtk_toggle_tool_button_new();
gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON(toolbar_item), "custom_icon");
If you have the image in different sizes, you can add them all and let Gtk choose the one of the correct size (or resize if not found): Just repeat the first five lines for each of the image files.
You can use your icon anywhere else and its size will also be adjusted automatically.
For example, to use it for your main window:
gtk_window_set_icon_name(GTK_WINDOW(main_window), "custom_icon");
Found it out myself! Here's the trick so that it helps someone like me. Query the icon size from the stock menu item, which is a enum (standard values like GTK_ICON_SIZE_BUTTON, GTK_ICON_SIZE_LARGE_TOOLBAR, etc.). Now get the pixel size using gtk_icon_size_lookup. Create a pixbuf from the custom icon/image file with the right dimensions. Create a GtkImage from that and set it to the new menu item and you're done!
GtkToolItem *stock_menu_item = gtk_toggle_tool_button_new_from_stock(GTK_STOCK_NEW);
GtkIconSize toolbar_icon_size = gtk_tool_item_get_icon_size(stock_menu_item);
gint width = 0, height = 0;
gtk_icon_size_lookup(toolbar_icon_size, &width, &height);
GdkPixbuf *app_icon = gdk_pixbuf_new_from_file_at_size(icon_file_path, width, height, NULL);
GtkImage *tray_icon = gtk_image_new_from_pixbuf(app_icon);
g_object_unref(app_icon);
app_icon = NULL;
GtkToolItem *toolbar_item = gtk_toggle_tool_button_new();
gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(toolbar_item), tray_icon);

FlashBuilder 4.5 :: Render Text without lifecycle for upsampling

I need to find a way to "upsample" text from 72dpi (screen) to 300dpi (print) for rendered client generated text. This is a true WYSIWYG application and we're expecting a ton of traffic so client side rendering is a requirement. Our application has several fonts, font sizes, colors, alignments the user can modify in a textarea. The question is how to convert 72dpi to 300dpi. We have the editior complete, we just need to make 300dpi versions of the textarea.
MY IDEA
1) Get textarea and increase the height, width, and font size by 300/72. (if ints are needed on font size I may need to increase the font then down-sample to the height/width)
2) use BitmapUtil.getSnapshot on the textarea to get a rendered version of the text
THE QUESTION
How can I render text inside of a textarea without the component lifecycle? Imagine:
var textArea:TextArea = new TextArea();
textArea.text = "This is a test";
var bmd:BitmapData = textArea.render();
Like Flextras said, width/height has nothing to do with DPI, unless you actually zoom into the application by 4.16X. If your application all has vector based graphics, it shouldn't be a problem. Plus, the concept of DPI is lost in any web application until you're trying to save/print a bitmap.
It's definitely possible, but you'll have to figure it on your own.
To ask a question another way, it is possible to create a TextArea in
memory which I can use the BitmapUtil.getSnapshot() function to
generate a BitmapData object
Technically, all components are in memory. What you want to do, I believe, is render a component without adding it to a container.
We do exactly this for the watermark on Flextras components. Conceptually we created a method to render the instance; like this:
public function render(argInheritingStyles : Object):void{
this.createChildren();
this.childrenCreated();
this.initializationComplete();
this.inheritingStyles = argInheritingStyles;
this.commitProperties();
this.measure();
this.height = this.measuredHeight;
this.width = this.measuredWidth;
this.updateDisplayList(this.unscaledWidth,this.unscaledHeight);
}
The method must be explicitly called. Then you can use the 'standard' procedure for turning the component into a bitmap. I think we use a Label; but the same approach should work on any given component.
Here is the final method I used to solve the problem of creating a printable version of the text and style of a Spark TextArea component. I ended up placing the custom component TextAreaRenderer (see below) in the MXML and setting the visibility to false. Then using the reference to this component to process any text field (renderObject) and get back a BitmapData object.
public class TextAreaRenderer extends TextArea implements IAssetRenderer
{
public function render(renderObject:Object, dpi:int = 300):BitmapData{
// CAST THE OBJECT
//.................
var userTextArea:TextArea = TextArea(renderObject);
// SCALE IS THE DIVISION OF THE NEW DPI OVER THE SCREEN DPI 72
//............................................................
var scale:Number = dpi / 72;
// COPY THE USER'S TEXT AREA INTO THE OFFSCREEN TEXT AREA
//.......................................................
this.text = userTextArea.text; // the actual text
this.height = Math.floor(userTextArea.height * scale); // scaled height
this.width = Math.floor(userTextArea.width * scale); // scaled width
// GET THE LAYOUT FORMATS AND COPY TO OFFSCREEN
// - the user's format = userTextAreaLayoutFormat
// - the hidden format = thisLayoutFormat
//...............................................
var editableLayoutProperties:Array = ['fontSize', 'fontFamily', 'fontWeight', 'fontStyle', 'textAlign', 'textDecoration', 'color']
userTextArea.selectAll();
var userTextAreaLayoutFormat:TextLayoutFormat = userTextArea.getFormatOfRange();
this.selectAll();
var thisLayoutFormat:TextLayoutFormat = this.getFormatOfRange();
for each(var prop:String in editableLayoutProperties){
thisLayoutFormat[prop] = userTextAreaLayoutFormat[prop];
}
// SCALE THE FONT SIZE
//....................
thisLayoutFormat.fontSize = thisLayoutFormat.fontSize * scale;
// SET THE FORMAT BACK IN THE TEXT BOX
//...................................
this.setFormatOfRange(thisLayoutFormat);
// REDRAW THE OFFSCREEN
// RETURN THE BITMAP DATA
//.......................
this.validateNow();
return BitmapUtil.getSnapshot(this);
}
}
Then calling the TextAreaRenderer after the text area is changed to get a scaled up bitmap.
// COPY THE DATA INTO THE OFFSCREEN COMPONENT
//............................................
var renderableComponent:IAssetRenderer = view.offScreenTextArea;
return renderableComponent.render(userTextArea, 300);
Thanks to the advice from www.Flextras.com for working through the issue with me.

Resources