I am searching for a long time on net. But no use.
Please help or try to give some ideas how to achieve this.
Any help will be appreciated.
I get the Matrix by ImageRenderInfo#GetImageCTM(), and get the X/Y coordiantors.
but it is always 0!
I have tried these api, GetStartPoint(), and GetImageCTM.
However, the X/Y coordinator is always 0 :-(
Note: I have some images in pdf in some positons(not the (0,0) coordinator).
void IRenderListener.RenderImage(ImageRenderInfo imgRenderInfo)
{
Matrix mtx = imgRenderInfo.GetImageCTM();
// x, y
float[] coordinate = new float[] { mtx[Matrix.I31], mtx[Matrix.I32] };
// Why the coordinate[0] and coordinate[1]
// are always be ZERO regardless the positon in Pdf
}
Answer to the question as is
I parsed the page contents of an arbitrary file I had at hands (the example PDF from this question) using a render listener with your implementation code plus output of the coordinates:
public void ExtractImageCoordinatesFromArchmodels()
{
using (PdfReader reader = new PdfReader(#"EVERMOTION ARCHMODELS VOL.78.pdf"))
{
PdfReaderContentParser parser = new PdfReaderContentParser(reader);
ImageCoordinatesRenderListener listener = new ImageCoordinatesRenderListener();
for (var i = 1; i <= reader.NumberOfPages; i++)
{
parser.ProcessContent(i, listener);
}
}
}
internal class ImageCoordinatesRenderListener : IRenderListener
{
public void BeginTextBlock()
{ }
public void EndTextBlock()
{ }
public void RenderText(TextRenderInfo renderInfo)
{ }
public void RenderImage(ImageRenderInfo renderInfo)
{
Matrix mtx = renderInfo.GetImageCTM();
// x, y
float[] coordinate = new float[] { mtx[Matrix.I31], mtx[Matrix.I32] };
Console.WriteLine("Image at {0}, {1}.", coordinate[0], coordinate[1]);
}
}
and the output was
Image at 6,00029, 52,15466.
Image at 19,84251, 363,4501.
Image at 294,091, 361,5604.
Image at 300,0336, 81,089.
Image at 15,59055, 72,94052.
Image at 5,322647, 340,7029.
Image at 288,5311, 386,0621.
Image at 291,7613, 69,35573.
Image at 28,50845, 53,13286.
Image at 41,2021, 380,3172.
Image at 290,8796, 368,9564.
Image at 295,8532, 50,71478.
Image at 19,13385, 49,21146.
Image at 25,5118, 385,9343.
Image at 282,4584, 379,8427.
Image at 293,5927, 65,19702.
Image at 4,535416, 60,35075.
Image at 3,364258, 374,4344.
Image at 288,0557, 373,5591.
Image at 299,9102, 59,13971.
Image at 11,33858, 66,10181.
Image at 11,66959, 380,3134.
Image at 297,1836, 378,4615.
Image at 299,9689, 66,74164.
Image at 10,62991, 53,18137.
Image at 5,180252, 377,7065.
Image at 279,9567, 377,9544.
Image at 289,9219, 69,23323.
Image at 6,400314, 68,17795.
Image at 11,33858, 361,2458.
Image at 297,1935, 373,4553.
Image at 299,8854, 68,30142.
Image at 7,086609, 68,13367.
Image at 3,82518, 352,3451.
Image at 287,9208, 373,4846.
Image at 294,6425, 68,3132.
Image at 41,2271, 68,15968.
Image at 5,709488, 356,2161.
Image at 304,9857, 373,593.
Image at 282,4557, 48,97745.
Image at 5,669281, 53,65367.
Image at 27,34265, 382,0123.
Image at 297,1409, 373,494.
Image at 300,0584, 50,23624.
Image at 7,245102, 68,23528.
Image at 8,503922, 380,1963.
Image at 290,1901, 355,9355.
Image at 287,2598, 60,53516.
Image at 5,102356, 68,01541.
Image at 17,00786, 378,9057.
Image at 296,8928, 373,5667.
Image at 299,9655, 68,04535.
(My locale uses a comma as decimal separator.)
So I cannot reproduce your claim
the X/Y coordinator is always 0
Thus, what you observed is either due to some issue of your remaining code or something special about all your test PDFs; probably they simply indeed all have their images positioned at 0,0
Clarifications from comments
Meanwhile the OP has clarified in comments that the images of interest are located in annotation appearance streams, not in the page content stream.
Coordinates therein are in the respective annotation appearance stream coordinate system which is implied by the appearance's bounding box (its BBox entry). This bounding box then optionally is transformed by the appearance matrix (its Matrix entry). The resulting four sided area then is scaled and moved into the annotation's rectangle (its Rect entry). And depending on page rotation and annotation properties, this rectangle may be rotated by a multiple of 90° relative to the page coordinates.
Thus, a general solution transforming those coordinates into the default user space coordinate system of the page requires some math.
Often, though, bitmaps in annotation appearances are filling the bounding box (nearly) completely. Often there is no appearance matrix. And often annotations rotate with the page.
Thus, an often good approximation is to simply use the annotation rectangle. This also is what the OP now uses.
I am desperately searching for a good cropping tool. There are a bunch out there, for example:
Croppic
Cropit
Jcrop
The most important thing that I am trying to find is a cropping tool, that crops images without making the cropped image low in resolution. You can hack this by using the canvas tag by resizing the image. This way the image itself stays native, only the representation is smaller.
DarkroomJS was also something near the solution, but, unfortunately, the downloaded demo did not work. I'll try to figure out whats wrong. Does someone know some great alternatives, or how to get the cropped images in...let's say "native" resolution?
Thanks in advance!
You are relying on the cropping tool to provide an interface for the users. the problem is that the image returned is sized to the interface and not the original image. Rather than me sifting through the various API's to see if they provide some way of controlling this behaviour (I assume at least some of them would) and because it is such a simple procedure I will show how to crop the image manually.
To use JCrop as an example
Jcrop provides various events for cropstart, cropmove, cropend... You can add a listener to listen to these events and keep a copy of the current cropping interface state
var currentCrop;
jQuery('#target').on('cropstart cropmove cropend',function(e,s,crop){
currentCrop = crop;
}
I don't know where you have set the interface size and I am assuming the events return the crop details at the interface scale
var interfaceSize = { //you will have to work this out
w : ?,
h : ?.
}
Your original image
var myImage = new Image(); // Assume you know how to load
So when the crop button is clicked you can create the new image by scaling the crop details back to the original image size, creating a canvas at the cropped size, drawing the image so that the cropped area is corectly positioned and returning the canvas as is or as a new image.
// image = image to crop
// crop = the current cropping region
// interfaceSize = the size of the full image in the interface
// returns a new cropped image at full res
function myCrop(image,crop,interfaceSize){
var scaleX = image.width / interfaceSize.w; // get x scale
var scaleY = image.height / interfaceSize.h; // get y scale
// get full res crop region. rounding to pixels
var x = Math.round(crop.x * scaleX);
var y = Math.round(crop.y * scaleY);
var w = Math.round(crop.w * scaleX);
var h = Math.round(crop.h * scaleY);
// Assume crop will never pad
// create an drawable image
var croppedImage = document.createElement("canvas");
croppedImage.width = w;
croppedImage.height = h;
var ctx = croppedImage.getContext("2d");
// draw the image offset so the it is correctly cropped
ctx.drawImage(image,-x,-y);
return croppedImage
}
You then only need to call this function when the crop button is clicked
var croppedImage;
myButtonElement.onclick = function(){
if(currentCrop !== undefined){ // ensure that there is a selected crop
croppedImage = myCrop(myImage,currentCrop,interfaceSize);
}
}
You can convert the image to a dataURL for download, and upload via
imageData = croppedImage.toDataURL(mimeType,quality) // quality is optional and only for "image/jpeg" images
My question is related to this previous question. What I want to achieve is to stack images (they have transparency), write a string on top, and save the photomontage / photocollage with full resolution.
#Override
protected void beforeMain(Form f) {
Image photoBase = fetchResourceFile().getImage("Voiture_4_3.jpg");
Image watermark = fetchResourceFile().getImage("Watermark.png");
f.setLayout(new LayeredLayout());
final Label drawing = new Label();
f.addComponent(drawing);
// Image mutable dans laquelle on va dessiner (fond blanc)
Image mutableImage = Image.createImage(photoBase.getWidth(), photoBase.getHeight());
drawing.getUnselectedStyle().setBgImage(mutableImage);
drawing.getUnselectedStyle().setBackgroundType(Style.BACKGROUND_IMAGE_SCALED_FIT);
// Paint all the stuff
paints(mutableImage.getGraphics(), photoBase, watermark, photoBase.getWidth(), photoBase.getHeight());
// Save the collage
Image screenshot = Image.createImage(photoBase.getWidth(), photoBase.getHeight());
f.revalidate();
f.setVisible(true);
drawing.paintComponent(screenshot.getGraphics(), true);
String imageFile = FileSystemStorage.getInstance().getAppHomePath() + "screenshot.png";
try(OutputStream os = FileSystemStorage.getInstance().openOutputStream(imageFile)) {
ImageIO.getImageIO().save(screenshot, os, ImageIO.FORMAT_PNG, 1);
} catch(IOException err) {
err.printStackTrace();
}
}
public void paints(Graphics g, Image background, Image watermark, int width, int height) {
g.drawImage(background, 0, 0);
g.drawImage(watermark, 0, 0);
g.setColor(0xFF0000);
// Upper left corner
g.fillRect(0, 0, 10, 10);
// Lower right corner
g.setColor(0x00FF00);
g.fillRect(width - 10, height - 10, 10, 10);
g.setColor(0xFF0000);
Font f = Font.createTrueTypeFont("Geometos", "Geometos.ttf").derive(220, Font.STYLE_BOLD);
g.setFont(f);
// Draw a string right below the M from Mercedes on the car windscreen (measured in Gimp)
g.drawString("HelloWorld",
(int) (848 ),
(int) (610)
);
}
This is the saved screenshot I get if I use the Iphone6 skin (the payload image is smaller than the original one and is centered). If I use the Xoom skin this is what I get (the payload image is still smaller than the original image but it has moved to the left).
So to sum it all up : why is the saved screenshot with Xoom skin different from the one I get with Iphone skin ? Is there anyway to directly save the graphics on which I paint in the paints method so that the saved image would have the original dimensions ?
Thanks a lot to anyone that could help me :-)!
Cheers,
You can save an image in Codename one using the ImageIO class. Notice that you can draw a container hierarchy into a mutable image using the paintComponent(Graphics) method.
You can do both approaches with draw image on mutable or via layouts. Personally I always prefer layouts as I like the abstraction but I wouldn't say the mutable image approach is right/wrong.
Notice that if you change/repaint a lot then mutable images are slower (this will not be noticeable for regular code or on the simulator) as they are forced to use the software renderer and can't use the GPU fully.
In the previous question it seems you placed the image with a "FIT" style which naturally drew it smaller than the containing container and then drew the image on top of it manually... This is problematic.
One solution is to draw everything manually but then you will need to do the "fit" aspect of drawing yourself. If you use layouts you should position everything based on the layouts including your drawing/text.
I have searched everywhere and i cannot find any solution after 2 days of trying.
The Problem:
I'm doing an image Viewer with "Fit Image to View" feature. I load a picture of say 3000+ pixels in my GraphicsView (which is a lot smaller ofcourse), scrollbars appear that's good. When i click my btnFitView and executed:
ui->graphicsView->fitInView(scene->sceneRect(),Qt::KeepAspectRatio);
This is down scaling right? After fitInView() all lines are pixelated. It looks like a saw went over the lines on the image.
For example: image of a car has lines, image of a texbook (letters become in very bad quality).
My code sample:
// select file, load image in view
QString strFilePath = QFileDialog::getOpenFileName(
this,
tr("Open File"),
"/home",
tr("Images (*.png *.jpg)"));
imageObject = new QImage();
imageObject->load(strFilePath);
image = QPixmap::fromImage(*imageObject);
scene = new QGraphicsScene(this);
scene->addPixmap(image);
scene->setSceneRect(image.rect());
ui->graphicsView->setScene(scene);
// on_btnFitView_Clicked() :
ui->graphicsView->fitInView(scene->sceneRect(),Qt::KeepAspectRatio);
Just before fitInView(), sizes are:
qDebug()<<"sceneRect = "<< scene->sceneRect();
qDebug()<<"viewRect = " << ui->graphicsView->rect();
sceneRect = QRectF(0,0 1000x750)
viewRect = QRect(0,0 733x415)
If it is necessary i can upload screenshots of original loaded image and fitted in view ?
Am i doing this right? It seems all examples on the Web work with fitInView for auto-fitting. Should i use some other operations on the pixmap perhaps?
SOLUTION
// LOAD IMAGE
bool ImgViewer::loadImage(const QString &strImagePath)
{
m_image = new QImage(strImagePath);
if(m_image->isNull()){
return false;
}
clearView();
m_pixmap = QPixmap::fromImage(*m_image);
m_pixmapItem = m_scene->addPixmap(m_pixmap);
m_scene->setSceneRect(m_pixmap.rect());
this->centerOn(m_pixmapItem);
// preserve fitView if active
if(m_IsFitInView)
fitView();
return true;
}
// TOGGLED FUNCTIONS
void ImgViewer::fitView()
{
if(m_image->isNull())
return;
this->resetTransform();
QPixmap px = m_pixmap; // use local pixmap (not original) otherwise image is blurred after scaling the same image multiple times
px = px.scaled(QSize(this->width(),this->height()),Qt::KeepAspectRatio,Qt::SmoothTransformation);
m_pixmapItem->setPixmap(px);
m_scene->setSceneRect(px.rect());
}
void ImgViewer::originalSize()
{
if(m_image->isNull())
return;
this->resetTransform();
m_pixmap = m_pixmap.scaled(QSize(m_image.width(),m_image.height()),Qt::KeepAspectRatio,Qt::SmoothTransformation);
m_pixmapItem->setPixmap(m_pixmap);
m_scene->setSceneRect(m_pixmap.rect());
this->centerOn(m_pixmapItem); //ensure item is centered in the view.
}
On downshrink this produces good quality. Here are some stats after calling these 2 functions:
// "originalSize()" : IMAGE SIZE = (1152, 2048)
// "originalSize()" : PIXMAP SIZE = (1152, 2048)
// "originalSize()" : VIEW SIZE = (698, 499)
// "originalSize()" : SCENE SIZE = (1152, 2048)
// "fitView()" : IMAGE SIZE = (1152, 2048)
// "fitView()" : PIXMAP SIZE = (1152, 2048)
// "fitView()" : VIEW SIZE = (698, 499)
// "fitView()" : SCENE SIZE = (280, 499)
There is a problem now, after call to fitView() look the size of scene? Much smaller.
And if fitView() is activated, and I now scale the image on wheelEvent (zoomIn/zoomOut), with the views scale function: scale(factor,factor); ..produces terrible result.
This doesn't happen with originalSize() where scene size is equal to image size.
Think of the view as a window into the scene.
Moving the view large amounts, either zooming in or out, will likely create images that don't look great. Rather than the image being scaled as you would expect, the view is just moving away from the scene and doing its best to render the image, but the image has not been scaled, just transformed in the scene.
Rather than using QGraphicsView::fitInView, keep the main image in memory and create a scaled version of the image with QPixamp::scaled, each time FitInView is selected, or the user zooms in / out. Then set this QPixmap on the QGraphicsPixmapItem with setPixmap.
You may also want to think about dropping the scroll bars and allowing the user to drag the image around the screen, which provides a better user interface, in my opinion; though of-course it depends on your requirements.
I am looking to make a photoshop action (maybe this isn't possible, any other application recommendations would be helpful as well). I want to take a collection of photos and make them a certain aspect ration, ex: 4:3.
So I have an image that is 150px wide by 200px high. What I would like to happen is the image's canvas is made to be 267px wide, with the new area filled with a certain color.
So there are two possibilities I can think of:
1) Photoshop actions could do this, but I would have to pull current height, multiply by 1.333333 and then put that value in the width box of the canvas resize. Is it possible to have calculated values in Photoshop actions?
2) Some other application has this feature built in.
Any help is greatly appreciated.
Wow, I see now (after writing the answer) that this was asked a long time ago. . . oh well. This script does the trick.
This Photoshop script will resize any image's canvas so that it has a 4:5 aspect ratio. You can change the aspect ratio applied by changing arWidth and arHeight. The fill color will be set to the current background color. You could create an action to open a file, apply this script, then close the file to do a batch process.
Shutdown Photoshop.
Copy this javascript into a new file named "Resize Canvas.jsx" in Photoshop's Presets\Scripts folder.
Start Photoshop and in the File - Scripts menu it should appear.
#target photoshop
main ();
function main ()
{
if (app.documents.length < 1)
{
alert ("No document open to resize.");
return;
}
// These can be changed to create images with different aspect ratios.
var arHeight = 4;
var arWidth = 5;
// Apply the resize to Photoshop's active (selected) document.
var doc = app.activeDocument;
// Get the image size in pixels.
var pixelWidth = new UnitValue (doc.width, doc.width.type);
var pixelHeight = new UnitValue (doc.height, doc.height.type);
pixelWidth.convert ('px');
pixelHeight.convert ('px');
// Determine the target aspect ratio and the current aspect ratio of the image.
var targetAr = arWidth / arHeight;
var sourceAr = pixelWidth / pixelHeight;
// Start by setting the current dimensions.
var resizedWidth = pixelWidth;
var resizedHeight = pixelHeight;
// The source image aspect ratio determines which dimension, if any, needs to be changed.
if (sourceAr < targetAr)
resizedWidth = (arWidth * pixelHeight) / arHeight;
else
resizedHeight = (arHeight * pixelWidth) / arWidth;
// Apply the change to the image.
doc.resizeCanvas (resizedWidth, resizedHeight, AnchorPosition.MIDDLECENTER);
}
Mind that the accepted answer from #user268911 may not work for you if the source image has different pixels/inch than 72. Because the UnitValue.convert function works correctly only with 72 px/inch. To be sure the conversion is correct for ever pixel/inch value, set baseUnit property as follows:
...
var pixelWidth = new UnitValue (doc.width, doc.width.type);
pixelWidth.baseUnit = UnitValue (doc.width.baseUnit, "in");
var pixelHeight = new UnitValue (doc.height, doc.height.type);
pixelHeight.baseUnit = UnitValue (doc.height.baseUnit, "in");
...
For more details about the conversion see "Converting pixel and percentage values" section of the Adobe JavaScript Tools Guide.
What languages do you know? ImageMagick has command line tools that can do this, but you'd need to know a scripting language to get the values and calculate the new ones.
For .NET, my company's product, DotImage Photo, is free and can do this (need to know C# or VB.NET)