Why X/Y coordinators of image in pdf are always ZERO by GetImageCTM? - image

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.

Related

Crop and save an image in Flutter without ui

I want to make an app that can crop image in a specific aspect ratio(device ratio).
But, i don't want any ui to show crop options.
Ok, here is an example,
If user tap on an image from the image list in the app the selected Image automatically (background process) crop (device ratio) & saved on the device without showing any crop related ui. How can i do this! Any function in dart by whom can crop an image without showing anything.
You can use copyCrop() with image:
Image copyCrop(Image src, int x, int y, int w, int h);
import 'dart:io';
import 'package:image/image.dart';
void main(List<String> argv) {
String path = argv[0];
Directory dir = Directory(path);
List files = dir.listSync();
List<int> trimRect;
for (var f in files) {
if (f is! File) {
continue;
}
List<int> bytes = f.readBytesSync();
Image image = decodeImage(bytes);
if (image == null) {
continue;
}
if (trimRect == null) {
trimRect = findTrim(image, mode: TrimMode.transparent);
}
Image trimmed = copyCrop(image, trimRect[0], trimRect[1],
trimRect[2], trimRect[3]);
String name = f.path.split(RegExp(r'(/|\\)')).last;
File('$path/trimmed-$name').writeBytesSync(encodeNamedImage(image, f.path));
}
}
I can confirm that Jim's answer is correct. Only thing I'd like to add to his answer is how to use the findTrim() method, which the docs don't explain properly. The key to use findTrim is to have an a sample image with target aspect ratio but it should also include base negative space as background. The findTrim() function basically takes information from a sample image and you can get the x,y coordinates as well as width,height if you don't want to manually calculate the x,y coordinates. The keyword here is negative space because if you just provide a target picture(say 4:3) to the findTrim() method, the function will simply crop the image from x,y coordinates which are 0,0 in this case. Having negative space that acts as place holder will make your work easier to clip the image.
For example to auto crop any 16:9 image to 4:3, have a 4:3 sample image with 16:9 negative space background. I have added the image as well which you can save to see for yourself.

How can put image back of paints which i drew?

The thing what I want to make is similar to paint program.
The problem is when I draw some lines(Not just lines. Whole things I drew are included in this case.), those lines only drawn back of a image I put in before I draw that.
At first, I thought it was just problem of code's order. But it wasn't.
I just want draw some lines on the image like paint program.
Like this:enter image description here
You can paint into a separate "layer" using PGraphics.
Once you initialise an instance you can use the typical drawing methods within beginDraw() / endDraw() (as the reference example suggests).
The only thing left is to save the final image which is simple enough using save()
Here's a modified example of Examples > Basics > Image > LoadDisplay which uses a separate PGraphics instance to draw into as the mouse is dragged and saves the final image when the s key is pressed:
/**
* Based on Examples > Basics > Image > Load and Display
*
* Images can be loaded and displayed to the screen at their actual size
* or any other size.
*/
PImage img; // Declare variable "a" of type PImage
// reference to layer to draw into
PGraphics paintLayer;
void setup() {
size(640, 360);
// The image file must be in the data folder of the current sketch
// to load successfully
img = loadImage("moonwalk.jpg"); // Load the image into the program
// create a separate layer to draw into
paintLayer = createGraphics(width,height);
}
void draw() {
// Displays the image at its actual size at point (0,0)
image(img, 0, 0);
// Displays the paint layer
image(paintLayer,0,0);
}
void mouseDragged(){
// use drawing commands between beginDraw() / endDraw() calls
paintLayer.beginDraw();
paintLayer.line(mouseX,mouseY,pmouseX,pmouseY);
paintLayer.endDraw();
}
void keyPressed(){
if(key == 's'){
saveFrame("annotated-image.png");
}
}

Is it possible to save a generated image in Codename One?

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.

GraphicsView fitInView() very pixelated result when downshrinking

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.

LibGDX - How to smooth out actor drawable when scaling a Scene2d stage?

This is my set-up:
stage = new Stage(1280, 800, false);
button = new Button(drawableUp, drawableDown);
stage.add(button);
this gets rendered as following:
#Override
public void render(float delta) {
Gdx.gl.glClearColor(RED,GREEN,BLUE,ALPHA);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act(delta);
stage.draw();
}
The issue is that when the stage is shown on 1280x800 the button looks like that:
If the stage is rescaled to e.g. 1280x736, the button drawable is scaled in the following way:
Is there a way to smooth out the edges somehow? Because right now it looks to me that the scaling is simply done by removing one pixel line in the upper half and one in the lower half of the picture.
Are you using filters anywhere in your code? If not, then try this:
texture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
Where texture is the texture object that you're using.

Resources