The size of PDF documents, how do I convert from millimeters to pixels using Spire.pdf? - pdf

The size of PDF documents, how do I convert from millimeters to pixels using Spire.pdf?
PdfDocument doc = new PdfDocument();
doc.PageScaling = PdfPrintPageScaling.ActualSize;
doc.LoadFromFile("myDocument.pdf");
foreach (PdfPageBase page in doc.Pages)
{
//Result returns the pixel type. But I want to show in millimeters
Console.WriteLine("PageSize: {0}X{1}", page.Size.Width, page.Size.Height);
}

The size of PDF pages is not expressed in pixels but in points.
1 inch = 72 points
1 inch = 25.4 mm
That leads to:
1 point = 0.352777778 mm

Related

pdfbox extract text by area units

I need to extract the address zip code from a pdf and I use the PDFTextStripperByArea class from pdfbox like in this example ExtractTextByArea. But what are the units of parameters in Rectangle rect = new Rectangle( 10, 280, 275, 60 ); From where must measure and to what units? If they are pixels then it is not convenient to measure pdf page component positions in pixels.
The y-coordinates are java coordinates (y == 0 is top), not PDF coordinates (y == 0 is bottom).
The units are 1/72 inch which is identical to pixels when you render the PDF at 100%.

UTM to WGS 84 conversion issue

I am trying to use ESRI latest land use data and downloaded a tif image from
https://www.arcgis.com/apps/instant/media/index.html?appid=fc92d38533d440078f17678ebc20e8e2
for example, shown here
https://lulctimeseries.blob.core.windows.net/lulctimeseriespublic/lc2021/16R_20210101-20220101.tif
When I load the image to ArcGIS pro, the longitude between A and B (corners) is 6 degrees, which is expected. The tif image is in WGS84/UTM 16N projection. I want to be able to find longitude and latitude of each pixels on the tif file, so I converted it to WGS 84 coordinate. However, after I converted it (by GDAL and ArcGIS), the longitude span between A and B is larger than 6 degrees. It looks like the transformer treat each grid on the image as equal distance instead of equal longitude/latitude. Am I doing something wrong here?
def wgs_transformer(img):
"""Giving geoio image, return two transformers from image crs to wgs84 and wgs84 to image crs
They can be used to translate between pixels and lat/long
"""
assert isinstance(img, geoio.base.GeoImage), 'img is not geoio.base.GeoImage type object'
old_cs= osr.SpatialReference()
old_cs.ImportFromWkt(img.ds.GetProjectionRef())
# create the new coordinate system
new_cs = osr.SpatialReference()
new_cs.ImportFromEPSG(4326)
# create a transform object to convert between coordinate systems
transform_img_wgs = osr.CoordinateTransformation(old_cs,new_cs)
transform_wgs_img = osr.CoordinateTransformation(new_cs, old_cs)
return transform_img_wgs, transform_wgs_img
def pixels_to_latlong(img, px, py, transform, arr=None, return_band=False):
"""Giving pixels x, y cordinates, return latitude and longitude
Args:
img: geoio.base.GeoImage
px: float, x cordinate
py: float, y cordinate
transfrom: osgeo.osr.CoordinateTransformation
arr: np array, band info of the img
return_band: bool, if Ture, return band info for the pixel
Returns:
latitude, longitude
"""
assert isinstance(img, geoio.base.GeoImage), 'img is not geoio.base.GeoImage type object'
assert isinstance(transform, osgeo.osr.CoordinateTransformation), 'transform has to be osgeo.osr.CoordinateTransformation object'
band, width, height = img.shape
assert 0 <= px < width and 0 <= py < height, f'px {px}, py {py} are beyond the img shape ({width}, {height})'
if return_band:
assert isinstance(arr, np.ndarray), 'arr needs to be numpy.ndarray'
lat, long, _ = transform.TransformPoint(*img.raster_to_proj(px, py))
if return_band:
band_val = arr[py-1, px-1]
return lat, long, band_val
else:
return lat, long, 0

Creating a transparency group or setting graphics state soft mask with PDFBox

I have a grayscale image that serves as a soft mask and I want to use it on a group of PDF objects (images or paths).
The mask and the objects do not necessarily use the same transformation matrix, and there might be more than one object to mask, so that excludes the possibility of using the SMask attribute of the ImageXObject dictionary.
So after reading some of the PDF specification, it looks like I should do the following: create a transparency group with the objects to mask, then draw it with the soft mask set on the graphics state.
Will that work? How can I achieve this, preferably with PDFBox?
Here's an example. I have these two images: the mask and another image.
The mask image is 200x200. It is drawn with the matrix [[4 0 100] [0 4 100]].
The image is 400x300. It is drawn with the matrix [[2 0 100] [0 2 150]].
Additionally, a 400x400 black square is drawn below the image with no transform matrix.
So a transparency group is created with the image and the square, then it's drawn with the mask image. Here's the expected result:
Rather ugly as far as the effect goes, but that's just an example.
As far as I can see establishing an extended graphics state soft mask is a very manual task in PDFBox. You can do so as follows:
try ( PDDocument document = new PDDocument() ) {
final PDImageXObject image = RETRIEVE PHOTO IMAGE;
final PDImageXObject mask = RETRIEVE MASK IMAGE;
PDTransparencyGroupAttributes transparencyGroupAttributes = new PDTransparencyGroupAttributes();
transparencyGroupAttributes.getCOSObject().setItem(COSName.CS, COSName.DEVICEGRAY);
PDTransparencyGroup transparencyGroup = new PDTransparencyGroup(document);
transparencyGroup.setBBox(PDRectangle.A4);
transparencyGroup.setResources(new PDResources());
transparencyGroup.getCOSObject().setItem(COSName.GROUP, transparencyGroupAttributes);
try ( PDFormContentStream canvas = new PDFormContentStream(transparencyGroup) ) {
canvas.drawImage(mask, new Matrix(400, 0, 0, 400, 100, 100));
}
COSDictionary softMaskDictionary = new COSDictionary();
softMaskDictionary.setItem(COSName.S, COSName.LUMINOSITY);
softMaskDictionary.setItem(COSName.G, transparencyGroup);
PDExtendedGraphicsState extendedGraphicsState = new PDExtendedGraphicsState();
extendedGraphicsState.getCOSObject().setItem(COSName.SMASK, softMaskDictionary);
PDPage page = new PDPage(PDRectangle.A4);
document.addPage(page);
try ( PDPageContentStream canvas = new PDPageContentStream(document, page) ) {
canvas.saveGraphicsState();
canvas.setGraphicsStateParameters(extendedGraphicsState);
canvas.setNonStrokingColor(Color.BLACK);
canvas.addRect(100, 100, 400, 400);
canvas.fill();
canvas.drawImage(image, new Matrix(400, 0, 0, 300, 100, 150));
canvas.restoreGraphicsState();
}
document.save(new File(RESULT_FOLDER, "SoftMaskedImageAndRectangle.pdf"));
}
The result:
If I were you, though, I would not use a bitmap image for the soft mask but instead a PDF gradient. The result most likely will be much less pixelated.

NSBitmapImageRep: Inconsistent set of values

I am trying to read a 12-bit grayscale (DICOM:MONOCHROME2) image. I can read DICOM RGB files fine. When I attempt to load a grayscale image into NSBitmapImageRep, I get the following error message:
Inconsistent set of values to create NSBitmapImageRep
I have the following code fragment:
NSBitmapImageRep *rep = [[NSBitmapImageRep alloc]
initWithBitmapDataPlanes : nil
pixelsWide : width
pixelsHigh : height
bitsPerSample : bitsStored
samplesPerPixel : 1
hasAlpha : NO
isPlanar : NO
colorSpaceName : NSCalibratedWhiteColorSpace
bytesPerRow : width * bitsAllocated / 8
bitsPerPixel : bitsAllocated];
With these values:
width = 256
height = 256
bitsStored = 12
bitsAllocated = 16
Nothing seems inconsistent to me. I have verified that the image is: width*height*2 in length. So I am pretty sure that it is in a 2-byte grayscale format. I have tried many variations of the parameters, but nothing works. If I change "bitsPerSample" to 16, the error message goes away, but I get a solid black image. The closest success that I have been able to achieve, is to set "bitsPerPixel" to zero. When I do this, I successfully produce an image but it is clearly incorrectly rendered (you can barely make out the original image). Please some suggestions!! I have tried a long time to get this to work and have checked the Stack overflow and the web (many times). Thanks very much for any help!
SOLUTION:
After the very helpful suggestions from LEADTOOLS Support, I was able to solve my problem. Here is the code fragment that works (assuming a MONOCHROME2 DICOM image):
// If, and only if, MONOCHROME2:
NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc]
initWithBitmapDataPlanes : &pixelData
pixelsWide : width
pixelsHigh : height
bitsPerSample : bitsAllocated /*bitsStored-this will not work*/
samplesPerPixel : samplesPerPixel
hasAlpha : NO
isPlanar : NO
colorSpaceName : NSCalibratedWhiteColorSpace
bytesPerRow : width * bitsAllocated / 8
bitsPerPixel : bitsAllocated];
int scale = USHRT_MAX / largestImagePixelValue;
uint16_t *ptr = (uint16_t *)imageRep.bitmapData;
for (int i = 0; i < width * height; i++) *ptr++ *= scale;
It is important to know about the Transfer Syntax (0002:0010) and Number of frames in the dataset. Also, try to get the value length and VR for Pixel Data (7FE0:0010) element. Using value length of the pixel data element you will be able to validate your calculation for uncompressed image.
As for displaying the image, you will also need the value for High Bit (0028:0102) and Pixel Representation (0028:0103). An image could be 16-bit allocated, 12-bit stored, high bit set to 15 and have one sample per pixel. That means 4 lest significant bits of each word do not contain pixel data. Pixel Representation when set to 1 means sign bit is the high bit in pixel sample.
In addition, you many need to apply modality LUT transformation (rescale slope and rescale intercept for linear transformation) when present in the dataset to prepare the data for display. At the end, you apply the VOI LUT transformation (Window center and Window Width) to display the image.

SVG image within a Batik JSVGCanvas is scaled down after rotation and setting bounding box

I have a problem with the rotation within a JSVGCanvas.
The user can load SVG images into a document page (JLayeredPane).
Every image displays in his own JSVGCanvas and has his own class.
The user can resize the image by dragging the endpoints and also move the image around.
The rotation works perfectly
(Basic and rotated situation)
Only the subsequent change of the bounding box of the Canvas results in a scaling, which no longer corresponds to the original size
(Finally after setting Boundingbox)
Code fragment in UpdateManager():
....
// calculating new canvas bounding box
AffineTransform at = AffineTransform.getRotateInstance(rotation*Math.PI/180.0,
originalX + originalW/2.0,
originalY + originalH/2.0);
Rectangle2D.Double rect = new Rectangle2D.Double(originalX, originalY, originalW, originalH);
Shape s = at.createTransformedShape(rect);
xx = s.getBounds2D().getX();
yy = s.getBounds2D().getY();
ww = s.getBounds2D().getWidth();
hh = s.getBounds2D().getHeight();
canvas.setRenderingTransform(AffineTransform.getRotateInstance(rotation*Math.PI/180.0,
originalW/2.0, originalH/2.0));
// this.setBounds() will do the stuff and also change the Canvas Bounds
setBounds(xx, yy, ww, hh);
....
I am grateful for any help.
Solved...
I have found the way to solve this problem:
....
// calculating new canvas bounding box
AffineTransform at = AffineTransform.getRotateInstance(rotation*Math.PI/180.0,
originalX + originalW/2.0,
originalY + originalH/2.0);
Rectangle2D.Double rect = new Rectangle2D.Double(originalX, originalY, originalW, originalH);
Shape s = at.createTransformedShape(rect);
xx = s.getBounds2D().getX();
yy = s.getBounds2D().getY();
ww = s.getBounds2D().getWidth();
hh = s.getBounds2D().getHeight();
double rotScale = originalW/ww;
double diffX = (originalW * rotScale - originalW) / 2.0 * -1.0;
double diffY = (originalH * rotScale - originalH) / 2.0 * -1.0;
AffineTransform af = AffineTransform.getScaleInstance(rotScale, rotScale);
af.preConcatenate(AffineTransform.getTranslateInstance(diffX, diffY));
af.preConcatenate(AffineTransform.getRotateInstance(rotation*Math.PI/180.0, originalW/2.0, originalH/2.0));
canvas.setRenderingTransform(af);
// this.setBounds() will do the stuff and also change the Canvas Bounds
setBounds(xx, yy, ww, hh);
....
Maybe this will help others having the same problem.
Picture solved