Is there an equivalent to contentWidth and contentHeight for spark images?
I can get the size of the image component itself, as well as the sourceWidth and sourceHeight properties to get the unscaled size of the image.
But I can't work out the scaled image width and height of the source as displayed in the image component.
Any help greatly appreciated.
Was just trying to solve this exact issue. An adequate solution I found was to use IMAGE_ID.transform.pixelBounds.height (or width). Note that this won't be set until after the updateComplete event fires for the image. No idea why FLEX doesn't have a simple scaledWidth property.
Try extending the Spark Image component to include 2 new read-only properties to provide the scaled width and height as an equivalent to contentWidth and contentHeight.
The following will create 2 new bindable properties to return the actual scaled width and height of the image displayed inside the Spark Image component.
/**
* Returns the width of the image display taking into account the actual
* constraints of the container. If no scaling has occurred the actual
* width of the control is returned.
*/
[Bindable(event="scaledWidthChanged")]
public function get scaledWidth():Number
{
var num:Number = this.width;
if (scaleMode == "letterbox")
{
try
{
if ( (width > 0) && (sourceWidth < sourceHeight) )
{
num = (sourceWidth/sourceHeight) * width;
}
}
catch(e:Error)
{
num = this.width;
}
}
return num;
}
/**
* Returns the height of the image display taking into account the actual
* constraints of the container. If no scaling has occurred the actual
* height of the control is returned.
*/
[Bindable(event="scaledHeightChanged")]
public function get scaledHeight():Number
{
var num:Number = this.width;
if (scaleMode == "letterbox")
{
try
{
if ((height > 0) && (sourceHeight < sourceWidth))
{
num = (sourceHeight/sourceWidth) * height;
}
}
catch(e:Error)
{
num = this.height;
}
}
return num;
}
Related
I have load an image in QGraphicsView, but consider of the size of QGraphicsView scene, I need to scale the image first, then add the scaled image to scene.
e.g. The image original size is 1536*1024, the QGraphicsView size is 500*400, firstly I scale the image like this:
image2D = image2D.scaled( h * P , h, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
myScene->setSceneRect((h * P-w)/2, 0, h * P , h);
pixmapItem = new QGraphicsPixmapItem(image2D);
myScene->addItem(pixmapItem);
myView->setScene(myScene);
And now a problem comes to me, when wheelEvent happends and the QGraphicsView zoom in, the scaled image becomes indistinct while I want it to keep as clear as the original one.
I find a way that I can hold an original copy of image, then when wheelEvent happend just scale the original copy and put it to scene.
But I don't know how to write this code, thanks for help~
or are there any simple methods?
class interactiveView : public QGraphicsView
{
protected:
void wheelEvent(QWheelEvent *event) override;
}
void interactiveView::wheelEvent(QWheelEvent *event)
{
int scrollAmount = event->delta();
xPos = event->pos().x();
yPos = event->pos().y();
scrollAmount > 0 ? zoomIn() : zoomOut();
}
Update:
I find a simple way like this:
just use QGraphicsView::fitInView() to make sure that the image scale is equal to QGraphicsView, and do not need to scale image first.
Therefore the image won't be indistinct when zoom in, and I only need to recall the QGraphicsView::fitInView() to reset to original view instead of using QGraphicsView::resetMatrix()
void myImageWindow::loadImag(int w, int h)
{
pixmapItem->setPixmap(image2D);
//if the scale of image changed
if(image2D.height() != imgHeight_pre){
myView->fitInView(pixmapItem, Qt::KeepAspectRatioByExpanding);
imgHeight_pre = image2D.height();
}
//if the scene of QGraphicsView changed
if(h != sceneHeight_pre){
myView->fitInView(pixmapItem, Qt::KeepAspectRatioByExpanding);
sceneHeight_pre = h;
}
}
void myImageWindow::on_rstImgBtn_clicked()
{
myView->fitInView(pixmapItem, Qt::KeepAspectRatioByExpanding);
}
Scaled image:
becomes indistinct when zoom in:
You can use this method resetMatrix() to reset image
For example:
graphicsView->scale(2, 2);
graphicsView->resetMatrix();
graphicsView->scale(1, 1);
I am rendering OSM map tiles onto a web page using HTML canvas drawImage. However where an end user has selected dark mode, I would like to reduce the luminosity of these displayed maps, yet still allow them to make sense to the user.
So far I have had moderate success, as follows:
First plotting the map tile using drawImage
setting globalCompositeOperation to "difference"
over plotting the map tile with a white rectangle of the same size
setting globalCompositeOperation back to "source-over"
But this simple colour inversion is not perhaps the best solution. Does anyone have any other suggestions.
You could switch to a different tile server with a different map style. Check for example "CartoDB.DarkMatter" from Leaflet Provider Demo or MapBox Light & Dark.
I have found a pretty good solution to this and it is as follows:
First set the canvas context filter to "hue-rotate(180deg)"
Then plot the map tile on the canvas using drawImage
Then set the canvas context filter to "none"
The set canvas context globalCompositeOperation to "difference"
Then over plot the map tile with a white rectangle of the same size
Finally set canvas context globalCompositeOperation back to "source-over"
Maybe someone will still find this useful, it's some code i'm using for this purpose in my tar1090 project.
Negative and positive contrast are probably clear and dim is basically just a brightness modification with inverted sign.
toggle function:
function setDim(layer, state) {
if (state) {
layer.dimKey = layer.on('postrender', dim);
} else {
ol.Observable.unByKey(layer.dimKey);
}
OLMap.render();
}
postrender function:
function dim(evt) {
const dim = mapDimPercentage * (1 + 0.25 * toggles['darkerColors'].state);
const contrast = mapContrastPercentage * (1 + 0.1 * toggles['darkerColors'].state);
if (dim > 0.0001) {
evt.context.globalCompositeOperation = 'multiply';
evt.context.fillStyle = 'rgba(0,0,0,'+dim+')';
evt.context.fillRect(0, 0, evt.context.canvas.width, evt.context.canvas.height);
} else if (dim < -0.0001) {
evt.context.globalCompositeOperation = 'screen';
console.log(evt.context.globalCompositeOperation);
evt.context.fillStyle = 'rgba(255, 255, 255,'+(-dim)+')';
evt.context.fillRect(0, 0, evt.context.canvas.width, evt.context.canvas.height);
}
if (contrast > 0.0001) {
evt.context.globalCompositeOperation = 'overlay';
evt.context.fillStyle = 'rgba(0,0,0,'+contrast+')';
evt.context.fillRect(0, 0, evt.context.canvas.width, evt.context.canvas.height);
} else if (contrast < -0.0001) {
evt.context.globalCompositeOperation = 'overlay';
evt.context.fillStyle = 'rgba(255, 255, 255,'+ (-contrast)+')';
evt.context.fillRect(0, 0, evt.context.canvas.width, evt.context.canvas.height);
}
evt.context.globalCompositeOperation = 'source-over';
}
toggle function when using LayerSwitcher:
function setDimLayerSwitcher(state) {
if (!state) {
ol.control.LayerSwitcher.forEachRecursive(layers_group, function(lyr) {
if (lyr.get('type') != 'base')
return;
ol.Observable.unByKey(lyr.dimKey);
});
} else {
ol.control.LayerSwitcher.forEachRecursive(layers_group, function(lyr) {
if (lyr.get('type') != 'base')
return;
lyr.dimKey = lyr.on('postrender', dim);
});
}
OLMap.render();
}
I have a quite simple unity GUI that has the following scheme :
Where Brekt and so are buttons.
The GUI works just fine on PC and is on screen space : overlay so it is supposed to be adapted automatically to fit every screen.
But on tablet the whole GUI is smaller and reduced in the center of the screen, with huge margins around the elements (can't join a screenshot now)
What is the way to fix that? Is it something in player settings or in project settings?
Automatically scaling the UI requires using combination of anchor,pivot point of RecTransform and the Canvas Scaler component. It is hard to understand it without images or videos. It is very important that you thoroughly understand how to do this and Unity provided full video tutorial for this.You can watch it here.
Also, when using scrollbar, scrollview and other similar UI controls, the ContentSizeFitter component is also used to make sure they fit in that layout.
There is a problem with MovementRange. We must scale this value too.
I did it so:
public int MovementRange = 100;
public AxisOption axesToUse = AxisOption.Both; // The options for the axes that the still will use
public string horizontalAxisName = "Horizontal"; // The name given to the horizontal axis for the cross platform input
public string verticalAxisName = "Vertical"; // The name given to the vertical axis for the cross platform input
private int _MovementRange = 100;
Vector3 m_StartPos;
bool m_UseX; // Toggle for using the x axis
bool m_UseY; // Toggle for using the Y axis
CrossPlatformInputManager.VirtualAxis m_HorizontalVirtualAxis; // Reference to the joystick in the cross platform input
CrossPlatformInputManager.VirtualAxis m_VerticalVirtualAxis; // Reference to the joystick in the cross platform input
void OnEnable()
{
CreateVirtualAxes();
}
void Start()
{
m_StartPos = transform.position;
Canvas c = GetComponentInParent<Canvas>();
_MovementRange = (int)(MovementRange * c.scaleFactor);
Debug.Log("Range:"+ _MovementRange);
}
void UpdateVirtualAxes(Vector3 value)
{
var delta = m_StartPos - value;
delta.y = -delta.y;
delta /= _MovementRange;
if (m_UseX)
{
m_HorizontalVirtualAxis.Update(-delta.x);
}
if (m_UseY)
{
m_VerticalVirtualAxis.Update(delta.y);
}
}
void CreateVirtualAxes()
{
// set axes to use
m_UseX = (axesToUse == AxisOption.Both || axesToUse == AxisOption.OnlyHorizontal);
m_UseY = (axesToUse == AxisOption.Both || axesToUse == AxisOption.OnlyVertical);
// create new axes based on axes to use
if (m_UseX)
{
m_HorizontalVirtualAxis = new CrossPlatformInputManager.VirtualAxis(horizontalAxisName);
CrossPlatformInputManager.RegisterVirtualAxis(m_HorizontalVirtualAxis);
}
if (m_UseY)
{
m_VerticalVirtualAxis = new CrossPlatformInputManager.VirtualAxis(verticalAxisName);
CrossPlatformInputManager.RegisterVirtualAxis(m_VerticalVirtualAxis);
}
}
public void OnDrag(PointerEventData data)
{
Vector3 newPos = Vector3.zero;
if (m_UseX)
{
int delta = (int)(data.position.x - m_StartPos.x);
delta = Mathf.Clamp(delta, -_MovementRange, _MovementRange);
newPos.x = delta;
}
if (m_UseY)
{
int delta = (int)(data.position.y - m_StartPos.y);
delta = Mathf.Clamp(delta, -_MovementRange, _MovementRange);
newPos.y = delta;
}
transform.position = new Vector3(m_StartPos.x + newPos.x, m_StartPos.y + newPos.y, m_StartPos.z + newPos.z);
UpdateVirtualAxes(transform.position);
}
I have created a usercontrol just to contain an Image, because I haveto use Measureoverride and arrangeoverride methods and I can't create a subclass (Image is seled)... anyway, the thing is that when i call this.Image.Measure(SizeIwantto giveto the image) the desiredSize field of the image is not set... anybody know why?
I have been managing the Layouting methods before and It worked...
Here is the code (I have already checked all the other sizes and none of them is 0 or NaN)
protected override Size MeasureOverride(Size availableSize)
{
//the size that the element wants to have
Size imageDesiredSize = new Size();
imageDesiredSize = availableSize;
//if the current element's size is a pertentage
if ((futureHeight != 0))
{
imageDesiredSize.Height = availableSize.Height * futureHeight / 100;
}
if ((futureWidth != 0))
{
imageDesiredSize.Width = availableSize.Width * futureWidth / 100;
}
if (widthWrap)
{
imageDesiredSize.Width = ((BitmapImage)this.Source).PixelWidth;
}
if (heightWrap)
{
imageDesiredSize.Height = ((BitmapImage)this.Source).PixelHeight;
}
System.Diagnostics.Debug.WriteLine("imagedesired" + imageDesiredSize);
this.image.Measure(imageDesiredSize);
System.Diagnostics.Debug.WriteLine("desiredsize" + this.image.DesiredSize);
return imageDesiredSize;
}
In the end It was a really simple solution... In the constructor of the UserControl I added this line: this.Content = image;
And now the content of the Usercontrol is drawn in the screen :-)
Is there a succinct example of how to upload an image, resize it, store it in a database and then serve the image up using Lift?
I'm sure I could piece it together from the file upload, Java 2D API, Lift Mapper and Response APIs. But is there any example code I can follow to do it the 'correct' or recommended way?
I did this for a Mapper field linked to s3 by creating a new MappedField. I also have a some code to resize, but haven't tested or deployed (so use with caution).
class MappedS3Image[T<:Mapper[T]](owner: T, val path:String, maxWidth: String, maxHeight:String) extends MappedString[T](owner, 36) {
def url:String = MappedS3Image.fullImgPath(path, is)
def setFromUpload(fileHolder: Box[FileParamHolder]) = {
S3Sender.uploadImageToS3(path, fileHolder).map(this.set(_))
}
override def asHtml:Node = <img src={url} style={"max-width:" + maxWidth + ";max-height:"+maxHeight} />
override def _toForm: Box[Elem] = Full(SHtml.fileUpload(fu=>setFromUpload(Full(fu))))
}
import java.awt.Image
import java.awt.image.BufferedImage
import javax.imageio.ImageIO
import java.awt.Graphics2D
import java.awt.AlphaComposite
object ImageResizer {
def resize(is:java.io.InputStream, maxWidth:Int, maxHeight:Int):BufferedImage = {
val originalImage:BufferedImage = ImageIO.read(is)
val height = originalImage.getHeight
val width = originalImage.getWidth
if (width <= maxWidth && height <= maxHeight)
originalImage
else {
var scaledWidth:Int = width
var scaledHeight:Int = height
val ratio:Double = width/height
if (scaledWidth > maxWidth){
scaledWidth = maxWidth
scaledHeight = (scaledWidth.doubleValue/ratio).intValue
}
if (scaledHeight > maxHeight){
scaledHeight = maxHeight
scaledWidth = (scaledHeight.doubleValue*ratio).intValue
}
val scaledBI = new BufferedImage(scaledWidth, scaledHeight, BufferedImage.TYPE_INT_RGB)
val g = scaledBI.createGraphics
g.setComposite(AlphaComposite.Src)
g.drawImage(originalImage, 0, 0, scaledWidth, scaledHeight, null);
g.dispose
scaledBI
}
}
}
The other answer nicely describes how to resize the image and store a reference to the file on the file system.
If you want to use the lift mapper to store the actual file contents, you have to create your custom model object, and define a binary field on it. Try something like this:
package code {
package model {
import _root_.net.liftweb.mapper._
import _root_.net.liftweb.util._
import _root_.net.liftweb.common._
// singleton object which manipulates storing of Document instances
object Document extends Document with KeyedMetaMapper[Long, Document] {
}
class Document extends KeyedMapper[Long, Document] {
def getSingleton = Document
def primaryKeyField = id
object id extends MappedLongIndex(this)
object name extends MappedString(this, 20) {
override def displayName = "Name"
override def writePermission_? = true
}
object content extends MappedBinary(this) {
override def displayName = "Content"
override def writePermission_? = true
}
}
}
}
Then, in bootstrap class, add this Document at the end:
Schemifier.schemify(true, Schemifier.infoF _, User, Document)
Voila. Using Document save (new Document) stores it into database. A new Document's fields can be set using the set method. Try playing with delete_!, find, findAll methods of the Document singleton to delete or find it in the database. It should be straightforward from this point on.
Finally, to display the image, you can override Lift's dispatching rules (in bootstrap class, Boot.scala). Try playing around with this example which overrides the rules for pdf requests:
def getFile(filename: String): Option[Document] = {
val alldocs = Document.findAll()
alldocs.find(_.name.get == filename)
}
LiftRules.statelessDispatchTable.append {
case Req("file" :: name :: Nil, "pdf", GetRequest) =>
() =>
println("Got request for: " + name + ".pdf")
for {
stream <- tryo(
getFile(name + ".pdf") map {
doc => new java.io.ByteArrayInputStream(doc.content.get)
} getOrElse null
)
if null ne stream
} yield StreamingResponse(stream,
() => stream.close,
stream.available,
List("Content-Type" -> "application/pdf"),
Nil,
200)
}
Based on the accepted answer by Jon Hoffman, I fixed the bugs. His version messes up the aspect ratio (it always becomes 1:1), because the math was off in a few spots. This version resizes big pictures until they fit, and respects the aspect ratio.
def resize(is:java.io.InputStream, maxWidth:Int, maxHeight:Int):BufferedImage = {
require (maxWidth > 0)
require (maxHeight > 0)
val originalImage:BufferedImage = ImageIO.read(is)
var height = originalImage.getHeight
var width = originalImage.getWidth
// Shortcut to save a pointless reprocessing in case the image is small enough already
if (width <= maxWidth && height <= maxHeight)
originalImage
else {
// If the picture was too big, it will either fit by width or height.
// This essentially resizes the dimensions twice, until it fits
if (width > maxWidth){
height = (height.doubleValue() * (maxWidth.doubleValue() / width.doubleValue())).intValue
width = maxWidth
}
if (height > maxHeight){
width = (width.doubleValue() * (maxHeight.doubleValue() / height.doubleValue())).intValue
height = maxHeight
}
val scaledBI = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB)
val g = scaledBI.createGraphics
g.setComposite(AlphaComposite.Src)
g.drawImage(originalImage, 0, 0, width, height, null);
g.dispose
scaledBI
}
}