C# Spoiler Code (Text): /// <summary> /// Returns a string of the pet OCR location required to complete a main shop purchase in Neopets. /// </summary> /// <param name="imgOCR">Required. The image to find the darkest pixel of (OCR in Neopets).</param> /// <param name="xSpeed">Optional. The increments of X to scan by.</param> /// <param name="ySpeed">Optional. The increments of Y to scan by.</param> /// <param name="xError">Optional. The integer to adjust the X value by before returning.</param> /// <param name="yError">Optional. The integer to adjust the Y value by before returning.</param> /// <param name="retBright">Optional. If this value is found, it will immediately return the X and Y values and stop checking for lower values.</param> /// <returns></returns> public string NeopetsOCR(Bitmap imgOCR, int xSpeed = 10, int ySpeed = 10, int xError = 10, int yError = 10, int retBright = 110) { System.Drawing.Imaging.BitmapData imgData = imgOCR.LockBits(new Rectangle(10, 10, imgOCR.Width - 11, imgOCR.Height - 11), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); int retX = 0, retY = 0; int curBright = 0; int maxBright = 255; int indxBright = 0; IntPtr ptrScan0 = imgData.Scan0; try { if (xSpeed + ySpeed < 4) { int[] rgbValues = new int[imgData.Width * imgData.Height + 1]; Marshal.Copy(ptrScan0, rgbValues, 0, rgbValues.Length); imgOCR.UnlockBits(imgData); for (int Y = 0; Y <= imgData.Height - 1; Y += ySpeed) { for (int X = 0; X <= imgData.Width - 1; X += xSpeed) { indxBright = (Y * (imgData.Width)) + X; curBright = (int)((0.2 * ((rgbValues[indxBright] & 0xff0000) / 65536)) + (0.7 * ((rgbValues[indxBright] & 0xff00) / 256)) + (0.1 * (rgbValues[indxBright] & 0xff))); if (curBright <= retBright) { return "&x=" + (X + xError + 10).ToString() + "&y=" + (Y + yError + 10).ToString(); } else if (curBright < maxBright) { retY = Y; retX = X; maxBright = curBright; } } } } else { for (int Y = 0; Y <= imgData.Height - 1; Y += ySpeed) { for (int X = 0; X <= imgData.Width - 1; X += xSpeed) { indxBright = Marshal.ReadInt32(ptrScan0, (imgData.Stride * Y) + (X * 4)); curBright = (int)((0.2 * ((indxBright & 0xff0000) / 65536)) + (0.7 * ((indxBright & 0xff00) / 256)) + (0.1 * (indxBright & 0xff))); if (curBright == 0) { return "&x=" + (X + xError + 10).ToString() + "&y=" + (Y + yError + 10).ToString(); } else if (curBright < maxBright) { maxBright = curBright; retX = X; retY = Y; } } } imgOCR.UnlockBits(imgData); } } catch (Exception ex) { //Do something } return "&x=" + (retX + xError + 10).ToString() + "&y=" + (retY + yError + 10).ToString(); } VB.NET Spoiler Code (Text): ''' <summary> ''' Returns a string of the pet OCR location required to complete a main shop purchase in Neopets. ''' </summary> ''' <param name="imgOCR">Required. The image to find the darkest pixel of (OCR in Neopets).</param> ''' <param name="xSpeed">Optional. The increments of X to scan by.</param> ''' <param name="ySpeed">Optional. The increments of Y to scan by.</param> ''' <param name="xError">Optional. The integer to adjust the X value by before returning.</param> ''' <param name="yError">Optional. The integer to adjust the Y value by before returning.</param> ''' <param name="retBright">Optional. If this value is found, it will immediately return the X and Y values and stop checking for lower values.</param> ''' <returns></returns> Public Function NeopetsOCR(imgOCR As Bitmap, Optional xSpeed As Integer = 10, Optional ySpeed As Integer = 10, Optional xError As Integer = 10, Optional yError As Integer = 10, Optional retBright As Integer = 110) As String Dim imgData As System.Drawing.Imaging.BitmapData = imgOCR.LockBits(New Rectangle(10, 10, imgOCR.Width - 11, imgOCR.Height - 11), System.Drawing.Imaging.ImageLockMode.[ReadOnly], System.Drawing.Imaging.PixelFormat.Format32bppArgb) Dim retX As Integer = 0, retY As Integer = 0 Dim curBright As Integer = 0 Dim maxBright As Integer = 255 Dim indxBright As Integer = 0 Dim ptrScan0 As IntPtr = imgData.Scan0 Try If xSpeed + ySpeed < 4 Then Dim rgbValues As Integer() = New Integer(imgData.Width * imgData.Height) {} Marshal.Copy(ptrScan0, rgbValues, 0, rgbValues.Length) imgOCR.UnlockBits(imgData) Dim Y As Integer = 0 While Y <= imgData.Height - 1 Dim X As Integer = 0 While X <= imgData.Width - 1 indxBright = (Y * (imgData.Width)) + X curBright = CInt(Math.Truncate((0.2 * ((rgbValues(indxBright) And &Hff0000) \ 65536)) + (0.7 * ((rgbValues(indxBright) And &Hff00) \ 256)) + (0.1 * (rgbValues(indxBright) And &Hff)))) If curBright <= retBright Then Return "&x=" & (X + xError + 10).ToString() & "&y=" & (Y + yError + 10).ToString() ElseIf curBright < maxBright Then retY = Y retX = X maxBright = curBright End If X += xSpeed End While Y += ySpeed End While Else Dim Y As Integer = 0 While Y <= imgData.Height - 1 Dim X As Integer = 0 While X <= imgData.Width - 1 indxBright = Marshal.ReadInt32(ptrScan0, (imgData.Stride * Y) + (X * 4)) curBright = CInt(Math.Truncate((0.2 * ((indxBright And &Hff0000) \ 65536)) + (0.7 * ((indxBright And &Hff00) \ 256)) + (0.1 * (indxBright And &Hff)))) If curBright = 0 Then Return "&x=" & (X + xError + 10).ToString() & "&y=" & (Y + yError + 10).ToString() ElseIf curBright < maxBright Then maxBright = curBright retX = X retY = Y End If X += xSpeed End While Y += ySpeed End While imgOCR.UnlockBits(imgData) End If Catch ex As Exception 'Do something End Try Return "&x=" & (retX + xError + 10).ToString() & "&y=" & (retY + yError + 10).ToString() End Function This is probably the fastest you will ever get a Neopets OCR in .NET to go. Although you really don't need it this fast cause you want to look human, it is still good to have the speed when you need it or when you're going all-out illegit. What it does: Returns on finding any pixel with a brightness of 0. Calculates whether the Marshal.Copy or Marshal.ReadInt32 methods are faster. I found that when the x and y speeds add up to anything less than 4, it is faster to use Marshal.Copy, while when you are going by increments of 10 and 15, it is a waste of time to Copy the whole image data to an array before reading it. Allows you to enter a specific xError and yError to add to the final OCR value, and specific xSpeed and ySpeed to find the right balance between speed and accuracy. I find that 10 for all of those values work perfectly fine. Cuts off 10 pixels each side as they don't usually contain the pet anyways. Saves more time. Return brightness can be set by a parameter. If this value is found, it will immediately return the X and Y values and stop checking for lower values. XML Documentation Returns a string that is needed for the POST data when buying an item from Neopets' main shops.
Haha, AU actually does a pretty nice job. Inversing the colors and finding the strongest red concentration in the picture -- idk, but AU always seems to be right on the edge of the picture. Although I do suggest calculating approximate luminance ((0.2*R) + (0.7*G) + (0.1*B)) which accounts for what the human eye sees, which is what this function does. The human eye sees the most green, followed by red and a little of blue.