How do I save an UIImage as BMP? - iphone

Can I save (write to file) UIImage object as bitmap file (.bmp extension) in iPhone’s document directory?
Thanks in advance.

I don’t think BMP is supported on iPhone. Maybe somebody wrote a category for UIImage that does saving into BMP, but I don’t know about any. I guess You’ll have to get the bitmap data from the UIImage and write them yourself, BMP is quite a simple file format. All you have to do is write out the header and then the uncompressed data. The header is a structure called BITMAPINFOHEADER, see MSDN. Getting the bitmap data of an UIImage is described in Apple’s Technical Q&A1509.

Right now I am not concerned about the size. Just want to know can I write image data as .bmp file.

Realize this is an old post, but in case someone finds it like I did looking for a solution.
I basically needed to FTP UIImage as a small BMP, so I hacked this crude class in MonoTouch.
I borrowed from zxing.Bitmap.cs and Example 1 from wikipedia BMP article. It appears to work. Might have been slicker to do an extension like AsBMP() or something like that.
(I don't know what the objective-c equivalent is, but hopefully this is helpful to someone.)
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using MonoTouch.CoreGraphics;
public class BitmapFileRGBA8888
{
public byte[] Data; // data needs to be BGRA
public const int PixelDataOffset = 54;
public BitmapFileRGBA8888(UIImage image)
{
CGImage imageRef = image.CGImage;
int width = imageRef.Width;
int height = imageRef.Height;
Initialize((uint)width, (uint)height);
CGColorSpace colorSpace = CGColorSpace.CreateDeviceRGB();
IntPtr rawData = Marshal.AllocHGlobal(height*width*4);
CGContext context = new CGBitmapContext(
rawData, width, height, 8, 4*width, colorSpace, CGImageAlphaInfo.PremultipliedLast
);
context.DrawImage(new RectangleF(0.0f,0.0f,(float)width,(float)height),imageRef); // RGBA
byte[] pixelData = new byte[height*width*4];
Marshal.Copy(rawData,pixelData,0,pixelData.Length);
Marshal.FreeHGlobal(rawData);
int di = PixelDataOffset;
int si;
for (int y = 0; y < height; y++)
{
si = (height-y-1) * 4 * width;
for (int x = 0; x < width; x++)
{
CopyFlipPixel(pixelData, si, Data, di);
di += 4; // destination marchs forward
si += 4;
}
}
}
private void CopyFlipPixel(byte[] Src, int Src_offset, byte[] Dst, int Dst_offset)
{
int S = Src_offset;
int D = Dst_offset + 2;
Dst[D--] = Src[S++]; // R
Dst[D--] = Src[S++]; // G
Dst[D--] = Src[S++]; // B
Dst[Dst_offset+3] = Src[S]; // alpha
}
private void Initialize(uint W, uint H)
{
uint RawPixelDataSize = W * H * 4;
uint Size = RawPixelDataSize + 14 + 40;
Data = new byte[Size];
Data[0] = 0x42; Data[1] = 0x4D; // BITMAPFILEHEADER "BM"
SetLong(0x2, Size); // file size
SetLong(0xA, PixelDataOffset); // offset to pixel data
SetLong(0xE, 40); // bytes in DIB header (BITMAPINFOHEADER)
SetLong(0x12, W);
SetLong(0x16, H);
SetShort(0x1A, 1); // 1 plane
SetShort(0x1C, 32); // 32 bits
SetLong(0x22, RawPixelDataSize);
SetLong(0x26, 2835); // h/v pixels per meter device resolution
SetLong(0x2A, 2835);
}
private void SetShort(int Offset, UInt16 V)
{
var byts = BitConverter.GetBytes(V);
if (!BitConverter.IsLittleEndian) Array.Reverse(byts);
Array.Copy(byts,0,Data,Offset,byts.Length);
}
private void SetLong(int Offset, UInt32 V)
{
var byts = BitConverter.GetBytes(V);
if (!BitConverter.IsLittleEndian) Array.Reverse(byts);
Array.Copy(byts,0,Data,Offset,byts.Length);
}
} // END CLASS
Basically
var Bmp = new BitmapFileRGBA8888(TempImage);
FTP.UploadBin(Bmp.Data, "test.bmp"); // or just write as binary file

Since BMP is not a compressed format, is this a good idea?
Presumably, image size is even more important on portable devices.

Related

Alternative to System.Drawing.Bitmap for Xamarin Forms

I need to use Bitmap class from System.Drawing.Bitmap, this is a function that works fine on windows Platform. But after I tried to run on Xamarin Forms, and installed nuget package System.Drawing, the program compiles correctly without errors.
But when running program I receive an error. Somehow seems to point to System.Drawing from windows, not the System.Drawing from the nuget package.
What I need to do is, get Photo from Camera and print it.
Below is the code to print. Problem is with "Bitmap" converter.
Tried several nuget packages, none worked:
System.Drawing.Common
Fast-Bitmap
Bitmap.Net
public byte[] PrintImage(byte[] PHOTO)
{
Bitmap bmp;
using (var ms = new MemoryStream(PHOTO))
{
bmp = new Bitmap(ms);
}
BitmapData data = GetBitmapData(bmp);
BitArray dots = data.Dots;
byte[] width = BitConverter.GetBytes(data.Width);
int offset = 0;
MemoryStream stream = new MemoryStream();
BinaryWriter bw = new BinaryWriter(stream);
// center command
bw.Write(27);
bw.Write('a');
bw.Write(1);
// print image
bw.Write((char)0x1B);
bw.Write('#');
bw.Write((char)0x1B);
bw.Write('3');
bw.Write((byte)24);
while (offset < data.Height)
{
bw.Write((char)0x1B);
bw.Write('*'); // bit-image mode
bw.Write((byte)33); // 24-dot double-density
bw.Write(width[0]); // width low byte
bw.Write(width[1]); // width high byte
for (int x = 0; x < data.Width; ++x)
{
for (int k = 0; k < 3; ++k)
{
byte slice = 0;
for (int b = 0; b < 8; ++b)
{
int y = (((offset / 8) + k) * 8) + b;
// Calculate the location of the pixel.
// It'll be at (y * width) + x.
int i = (y * data.Width) + x;
// If the image is shorter than 24 dots.
bool v = false;
if (i < dots.Length)
{
v = dots[i];
}
slice |= (byte)((v ? 1 : 0) << (7 - b));
}
bw.Write(slice);
}
}
offset += 24;
bw.Write((char)0x0A);
}
// Restore the line spacing to the default of 30 dots.
bw.Write((char)0x1B);
bw.Write('3');
bw.Write((byte)30);
bw.Flush();
byte[] bytes = stream.ToArray();
return bytes; // logo + Encoding.Default.GetString(bytes);
}
public BitmapData GetBitmapData(Bitmap bmp) // (string bmpFileName)
{
//using (var bitmap = (Bitmap)Bitmap.FromFile(bmpFileName))
using (var bitmap = bmp)
{
var threshold = 127;
var index = 0;
double multiplier = 570; // this depends on your printer
double scale = (double)(multiplier / (double)bitmap.Width);
int xheight = (int)(bitmap.Height * scale);
int xwidth = (int)(bitmap.Width * scale);
var dimensions = xwidth * xheight;
var dots = new BitArray(dimensions);
for (var y = 0; y < xheight; y++)
{
for (var x = 0; x < xwidth; x++)
{
var _x = (int)(x / scale);
var _y = (int)(y / scale);
var color = bitmap.GetPixel(_x, _y);
var luminance = (int)(color.R * 0.3 + color.G * 0.59 + color.B * 0.11);
dots[index] = (luminance < threshold);
index++;
}
}
return new BitmapData()
{
Dots = dots,
Height = (int)(bitmap.Height * scale),
Width = (int)(bitmap.Width * scale)
};
}
}
public class BitmapData
{
public BitArray Dots
{
get;
set;
}
public int Height
{
get;
set;
}
public int Width
{
get;
set;
}
}
Error occurs when function is called as:
byte[] _buffer = PrintImage(FOTO);
The error:
"Could not resolve type with token 01000119 from typeref (expected class 'System.Drawing.Bitmap' in assembly 'System.Drawing.Common, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51')"

Unity3d code size differs from UI size

I got a square in Unity with a size of 500x500(slightly transparent).
Additionally, I want to take a snapshot of this area. Therefore, I created the following code for taking a picture(the area has got a size of 500x500).
public class CameraShot : MonoBehaviour{
private int width = 500;
private int height = 500;
private string saveFolder = "/picture";
private string saveType = ".png";
public void MakePicture()
{
var texture = SetClipping();
EncodeAndSafe(texture);
}
private Texture2D SetClipping()
{
int x = (Screen.width - width) / 2;
int y = (Screen.height - height) / 2;
Debug.Log("[AR_Recognition] CameraShot: " + Screen.dpi);
var tex = new Texture2D(width, height, TextureFormat.RGB24, false);
Rect rect = new Rect(x, y, width, height);
tex.ReadPixels(rect, 0, 0);
tex.Apply();
return tex;
}
private void EncodeAndSafe(Texture2D texture)
{
int count = 1;
var bytes = texture.EncodeToPNG();
Destroy(texture);
string savePath = Application.persistentDataPath + saveFolder;
while (true) {
if (System.IO.File.Exists(savePath))
{
count++;
}
else
{
File.WriteAllBytes(savePath+count+saveType, bytes);
Debug.Log("[AR_Recognition] CameraShot: " + savePath + saveType);
break;
}
}
}
Now I got the following issue:
The picture taken is not matching the 500x500 square but I cannot figure out why.
Ty
EDIT: The Canvas information

Detect color pages or BW pages in PDF

Is there any way that I can detect color pages in a PDF file?
For example I have a PDF file with 5 pages, and the first and last page are in color. How can I detect the color pages? Can iText do it?
Now my solution is to convert PDF to images and then detect images color or black&white, but it takes too long time to do it, I need a fast way.
Convert pdf to image by Adobe Acrobat Code as fellows
public static void ConvertPDF2Image(string pdfInputPath, string imageOutputPath,
string imageName, int startPageNum, int endPageNum, ImageFormat imageFormat, double resolution)
{
Acrobat.CAcroPDDoc pdfDoc = null;
Acrobat.CAcroPDPage pdfPage = null;
Acrobat.CAcroRect pdfRect = null;
Acrobat.CAcroPoint pdfPoint = null;
// Create the document (Can only create the AcroExch.PDDoc object using late-binding)
// Note using VisualBasic helper functions, have to add reference to DLL
pdfDoc = (Acrobat.CAcroPDDoc)Microsoft.VisualBasic.Interaction.CreateObject("AcroExch.PDDoc", "");
// validate parameter
if (!pdfDoc.Open(pdfInputPath)) { throw new FileNotFoundException(); }
if (!Directory.Exists(imageOutputPath)) { Directory.CreateDirectory(imageOutputPath); }
if (startPageNum <= 0) { startPageNum = 1; }
if (endPageNum > pdfDoc.GetNumPages() || endPageNum <= 0) { endPageNum = pdfDoc.GetNumPages(); }
if (startPageNum > endPageNum) { int tempPageNum = startPageNum; startPageNum = endPageNum; endPageNum = startPageNum; }
if (imageFormat == null) { imageFormat = ImageFormat.Jpeg; }
if (resolution <= 0) { resolution = 1; }
// start to convert each page
for (int i = startPageNum; i <= endPageNum; i++)
{
pdfPage = (Acrobat.CAcroPDPage)pdfDoc.AcquirePage(i - 1);
pdfPoint = (Acrobat.CAcroPoint)pdfPage.GetSize();
pdfRect = (Acrobat.CAcroRect)Microsoft.VisualBasic.Interaction.CreateObject("AcroExch.Rect", "");
int imgWidth = (int)((double)pdfPoint.x * resolution);
int imgHeight = (int)((double)pdfPoint.y * resolution);
pdfRect.Left = 0;
pdfRect.right = (short)imgWidth;
pdfRect.Top = 0;
pdfRect.bottom = (short)imgHeight;
// Render to clipboard, scaled by 100 percent (ie. original size)
// Even though we want a smaller image, better for us to scale in .NET
// than Acrobat as it would greek out small text
pdfPage.CopyToClipboard(pdfRect, 0, 0, (short)(100 * resolution));
IDataObject clipboardData = Clipboard.GetDataObject();
if (clipboardData.GetDataPresent(DataFormats.Bitmap))
{
Bitmap pdfBitmap = (Bitmap)clipboardData.GetData(DataFormats.Bitmap);
pdfBitmap.Save(Path.Combine(imageOutputPath, imageName) + i.ToString() + "." + imageFormat.ToString(), imageFormat);
pdfBitmap.Dispose();
}
}
pdfDoc.Close();
Marshal.ReleaseComObject(pdfPage);
Marshal.ReleaseComObject(pdfRect);
Marshal.ReleaseComObject(pdfDoc);
Marshal.ReleaseComObject(pdfPoint);
}
////detect image Color or black and white as fellows
Bitmap box1 = new Bitmap(PictureBox1.Image);
Color c = new Color()
int rr, gg, bb;
for(int i=0;i<PictureBox1.Width;i++){
for(int j=0;j<PictureBox1.Height;j++){
c= box1.GetPixel(i,j);
rr= c.R; gg=c.g;bb=c.B;
if(c ==Color.Black||c= Color.White){
MessageBox.Show("black and white dot")
}
else {
if(rr==gg==bb){
MessageBox.Show("Gray dot");
}
else {
MessageBOx.Show("Color dot");
}
}
}
}

EmguCV + Unity Open WebCam is Error;

I use EmguCV open webcam in unity.
But it's fps is low much.
this is my code ↓
private Texture2D texture;
private Capture capture;
private Color32[] color = new Color32[640*480];
// Use this for initialization
void Start () {
texture = new Texture2D (640, 480);
capture = new Capture ();
}
// Update is called once per frame
void Update () {
Image<Bgr, Byte> currentFrame = capture.QueryFrame();
Bitmap bitmapCurrentFrame = currentFrame.ToBitmap();
Image<Bgra, Byte> img = new Image<Bgra, Byte> (bitmapCurrentFrame);
for(int y=0; y<480; y++){
for(int x=0; x<640; x++){
int index = y+x*480;
print(index+";"+x+";"+y);
//byte b = img.Data[x,y,0];
color[index].r = img.Data[x,y,2];
color[index].g = img.Data[x,y,1];
color[index].b = img.Data[x,y,0];
color[index].a = 0xff;
}
}
texture.SetPixels32 (color);
texture.Apply (false);
renderer.material.mainTexture = texture;
}
i don't know why fps is so low...
and why my boss like EmguCV with Unity, why he don't use Unity-WebCamTexture...
OKAY,i really thank you for your read.
Hope, I can get some answer.
Look at Texture2D.LoadRawTextureData. It has no proper docs, so here's a snippet:
Texture2D tex = new Texture2D(width, height, format, false, true);
tex.LoadRawTextureData(buffer);
tex.Apply(false, true);
Buffer must be in the correct hardware format. For the format variable look at the list of formats that unity accepts.

QRCode encoding and decoding problem

I want to split a file ( a docx file) and use the individual fragments of the file to encode a QRCode such that when the qrcodes are read in sequence, it reproduces the original file.
I was able to split the file and create a bunch of QRCodes but when attempted to recreate the file, the Decoder throws the following Error Message.
"Invalid number of finder pattern detected"
I am using http://www.codeproject.com/KB/cs/qrcode.aspx library.
My encoder code
private List Encode(String content, Encoding encoding, int
System.Drawing.Color qrCodeBackgroundColor,
QRCodeCapacity,System.Drawing.Color qrCodeBackgroundColor,System.Drawing.Color
qrCodeForegroundColor,int qrCodeScale, int NoOfQRcodes)
{
List<Bitmap> _qrcodesImages = new List<Bitmap>();
byte[] _filebytearray = encoding.GetBytes(content);
for (int k = 0,l=0; k < NoOfQRcodes; k++)
{
byte[] _tempByteArray = _filebytearray.Skip(l).Take(QRCodeCapacity).ToArray();
bool[][] matrix = calQrcode(_tempByteArray);
SolidBrush brush = new SolidBrush(qrCodeBackgroundColor);
Bitmap image = new Bitmap((matrix.Length * qrCodeScale) + 1, (matrix.Length * qrCodeScale) + 1);
Graphics g = Graphics.FromImage(image);
g.FillRectangle(brush, new Rectangle(0, 0, image.Width, image.Height));
brush.Color = qrCodeForegroundColor;
for (int i = 0; i < matrix.Length; i++)
{
for (int j = 0; j < matrix.Length; j++)
{
if (matrix[j][i])
{
g.FillRectangle(brush, j * qrCodeScale, i * qrCodeScale, qrCodeScale, qrCodeScale);
}
}
}
_qrcodesImages.Add(image);
l += QRCodeCapacity;
}
return _qrcodesImages;
}